Выход из цикла FOR в командном файле? - PullRequest
21 голосов
/ 18 июля 2011

Почему этот пакетный файл никогда не выходит из цикла?

For /L %%f In (1,1,1000000) Do @If Not Exist %%f Goto :EOF

Разве Goto :EOF не должен вырваться из цикла?

Edit:

Полагаю, мне следовало бы спросить более четко ... как можно выйти из цикла?

Ответы [ 6 ]

6 голосов
/ 18 июля 2011

Вы можете просто использовать echo on, и вы увидите, что goto :eof или даже exit /b не работает должным образом.

Код внутри цикла больше не выполняется, но цикл расширяется для всех чисел до конца.
Вот почему он такой медленный.

Единственный способ выйтицикл FOR / L, кажется, является вариантом exit, как пример Wimmel, но это не очень быстро и не полезно для доступа к каким-либо результатам цикла.

Это показывает 10 расширений, но ни одногоиз них будут казнены

echo on
for /l %%n in (1,1,10) do (
  goto :eof
  echo %%n
)
6 голосов
/ 18 июля 2011

На основании второго редактирования Тима и этой страницы вы можете сделать это:

@echo off
if "%1"=="loop" (
  for /l %%f in (1,1,1000000) do (
    echo %%f
    if exist %%f exit
  )
  goto :eof
)
cmd /v:on /q /d /c "%0 loop"
echo done

На этой странице предлагается способ использовать goto внутри цикла, кажется, он работает, но в большом цикле это занимает некоторое время. Таким образом, внутренне он завершает цикл до выполнения goto.

2 голосов
/ 19 декабря 2016

Итак, я понимаю, что это довольно старо, но после долгих поисков я не смог найти ответ, который меня порадовал, поэтому я нашел собственное решение для разрыва цикла FOR, которое немедленно останавливает итерацию, и подумал, что поделился бы этим.

Требуется, чтобы цикл находился в отдельном файле, и использует ошибку в обработке ошибок CMD для немедленного сбоя пакетной обработки файла цикла при перенаправлении STDOUT DIR в STDIN.

MainFile.cmd

ECHO Simple test demonstrating loop breaking.
ECHO.
CMD /C %~dp0\LOOP.cmd
ECHO.
ECHO After LOOP
PAUSE

LOOP.cmd

FOR /L %%A IN (1,1,10) DO (
    ECHO %%A
    IF %%A EQU 3 DIR >&0 2>NUL  )
)

При запуске это приводит к следующему выводу. Вы заметите, что итерация и выполнение цикла прекращается, когда% A = 3.

:>MainFile.cmd

:>ECHO Simple test demonstrating loop breaking.
Simple test demonstrating loop breaking.

:>ECHO.


:>CMD /C Z:\LOOP.cmd

:>FOR /L %A IN (1 1 10) DO (
ECHO %A
 IF %A EQU 3 DIR         1>&0 2>NUL
)

:>(
ECHO 1
 IF 1 EQU 3 DIR          1>&0 2>NUL
)
1

:>(
ECHO 2
 IF 2 EQU 3 DIR          1>&0 2>NUL
)
2

:>(
ECHO 3
 IF 3 EQU 3 DIR          1>&0 2>NUL
)
3

:>ECHO.


:>ECHO After LOOP
After LOOP

:>PAUSE
Press any key to continue . . .

Если вам нужно сохранить одну переменную из цикла, сделайте цикл ECHO результатом переменной и используйте цикл FOR / F в MainFile.cmd для анализа вывода файла LOOP.cmd.

Пример (используется тот же файл LOOP.cmd, что и выше):

MainFile.cmd

@ECHO OFF
ECHO.
ECHO Simple test demonstrating loop breaking.
ECHO.
FOR /F "delims=" %%L IN ('CMD /C %~dp0\LOOP.cmd') DO SET VARIABLE=%%L
ECHO After LOOP
ECHO.
ECHO %VARIABLE%
ECHO.
PAUSE

Выход:

:>MainFile.cmd

Simple test demonstrating loop breaking.

After LOOP

3

Press any key to continue . . .

Если вам нужно сохранить несколько переменных, вам нужно перенаправить их во временные файлы, как показано ниже.

MainFile.cmd

@ECHO OFF
ECHO.
ECHO Simple test demonstrating loop breaking.
ECHO.
CMD /C %~dp0\LOOP.cmd
ECHO After LOOP
ECHO.
SET /P VARIABLE1=<%TEMP%\1
SET /P VARIABLE2=<%TEMP%\2
ECHO %VARIABLE1%
ECHO %VARIABLE2%
ECHO.
PAUSE

LOOP.cmd

@ECHO OFF
FOR /L %%A IN (1,1,10) DO (
    IF %%A EQU 1 ECHO ONE >%TEMP%\1
    IF %%A EQU 2 ECHO TWO >%TEMP%\2
    IF %%A EQU 3 DIR >&0 2>NUL
)

Выход:

:>MainFile.cmd

Simple test demonstrating loop breaking.

After LOOP

ONE
TWO

Press any key to continue . . .

Я надеюсь, что другие найдут это полезным для прерывания циклов, которые в противном случае вышли бы слишком долго из-за продолжающейся итерации.

2 голосов
/ 28 января 2016

Как отметили jeb , остаток цикла пропускается , но оценивается , что делает решение FOR слишком медленным для этой цели. Альтернатива:

set F=1
:nextpart
if not exist "%F%" goto :EOF
echo %F%
set /a F=%F%+1
goto nextpart

Вам может понадобиться использовать отложенное расширение и call подпрограммы при использовании этого в циклах.

0 голосов
/ 13 апреля 2015

Предполагая, что OP вызывает командный файл с cmd.exe, чтобы правильно выйти из цикла for, просто перейдите к метке;

Изменить это:

For /L %%f In (1,1,1000000) Do If Not Exist %%f Goto :EOF

К этому:

For /L %%f In (1,1,1000000) Do If Not Exist %%f Goto:fileError
.. do something
.. then exit or do somethign else

:fileError
GOTO:EOF

Еще лучше, добавить сообщение об ошибке:

set filename=
For /L %%f In (1,1,1000000) Do(
    set filename=%%f
    If Not Exist %%f set tempGoto:fileError
)
.. do something
.. then exit or do somethign else

:fileError
echo file does not exist '%filename%'
GOTO:EOF

Я считаю, что это полезный сайт о малоизвестных функциях и приемах командного файла cmd.exe / DOS: https://www.dostips.com/

0 голосов
/ 18 июля 2011

Небольшое исследование по этому вопросу, похоже, что вы делаете цикл от 1 до 2147483647 с шагом 1.

(1, 1, 2147483647): первый номер - начальный номер, следующий номер - шаг, а последний номер - конечный номер.

Отредактировано, чтобы добавить

Похоже, что цикл запускается до завершения независимо от условий тестирования. Я проверял

FOR /L %%F IN (1, 1, 5) DO SET %%F=6

И это очень быстро.

Второе редактирование

Поскольку это единственная строка в пакетном файле, вы можете попробовать команду EXIT:

FOR /L %%F IN (1, 1, 2147483647) DO @IF NOT EXIST %%F EXIT

Однако это также закроет окно приглашения DOS.

...