退出批处理文件中的FOR循环?

时间:2011-07-18 05:02:27

标签: batch-file for-loop break

为什么这个批处理文件永远不会脱离循环?

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

Goto :EOF不应该突破循环吗?

编辑:

我想我应该更明确地询问...... 我怎样才能摆脱循环?

8 个答案:

答案 0 :(得分:6)

基于Tim's second editthis page,你可以这样做:

@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

This page建议一种在循环中使用goto的方法,它似乎确实有效,但在大循环中需要一些时间。所以在内部它在执行goto之前完成循环。

答案 1 :(得分:6)

您只需使用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
)

答案 2 :(得分:3)

我的答案
使用嵌套的for循环为for /l循环提供断点。

for %%a in (0 1 2 3 4 5 6 7 8 9) do (
   for %%b in (0 1 2 3 4 5 6 7 8 9) do (
      for /l %%c in (1,1,10) do (
         if not exist %%a%%b%%c goto :continue
      )
   )
)
:continue

说明 必须对代码进行重大调整,以正确使用嵌套循环。例如,写入的内容将带有前导零。
可以通过简单的for命令立即打破“常规” goto循环,而for /l循环则不能。该代码最里面的for /l循环无法立即中断,但每10次迭代(写时)会出现一个总断点。最内层的循环不必是10次迭代-如果您选择对此事进行100或1000或2873运算,则只需要正确地考虑数学即可(如果数学甚至对循环很重要)。

历史 我在试图弄清楚为什么某个脚本运行缓慢时发现了这个问题。事实证明,我使用了具有传统循环结构的多个循环:

set cnt=1
:loop
if "%somecriteria%"=="finished" goto :continue
rem do some things here
set /a cnt += 1
goto :loop

:continue
echo the loop ran %cnt% times

此脚本文件已变得有些长,并且正在从网络驱动器运行。这种类型的循环文件可能被调用了20次,每次循环执行50-100次。脚本文件耗时太长。我有一个绝妙的主意,尝试将其转换为for /l循环。所需的迭代次数未知,但少于10000。我的第一次尝试是:

setlocal enabledelayedexpansion
set cnt=1
for /l %%a in (1,1,10000) do (
   if "!somecriteria!"=="finished" goto :continue
   rem do some things here
   set /a cnt += 1
)

:continue
echo the loop ran %cnt% times

启用echo后,我很快发现for /l循环仍然可以执行... 某事 ...而无需实际上做任何事情。它的运行速度快得多,但仍然比我认为的可能/慢。因此,我找到了这个问题,并最终得出了上面介绍的嵌套循环的想法。

旁注 事实证明,只需确保没有任何输出,就可以大大加快for /l循环的速度。我能够做到这一点,从而显着提高了速度:

setlocal enabledelayedexpansion
set cnt=1
@for /l %%a in (1,1,10000) do @(
   if "!somecriteria!"=="finished" goto :continue
   rem do some things here
   set /a cnt += 1
) > nul

:continue
echo the loop ran %cnt% times

答案 3 :(得分:2)

作为jeb noted,循环的其余部分被跳过但已评估,这使得FOR解决方案为此目的而过慢。另一种选择:

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

在循环中使用时,您可能需要使用delayed expansioncall子例程。

答案 4 :(得分:2)

所以我意识到这有点老了,但经过Google搜索后,我无法找到我满意的答案,所以我提出了自己的解决方案来打破FOR循环,立即停止迭代,并且以为我会分享它。

它要求循环位于单独的文件中,并利用CMD错误处理中的错误,在将DIR的STDOUT重定向到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作为变量的结果,并使用MainFile.cmd中的FOR / F循环来解析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 . . .

我希望其他人发现这对于打破循环非常有用,否则由于持续迭代而需要很长时间才能退出。

答案 5 :(得分:0)

对此做了一点研究,看来你从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提示窗口。

答案 6 :(得分:0)

假设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/

答案 7 :(得分:0)

如果您使用call而不是像

这样的goto,则不需要单独的批处理文件即可使用exit / b退出循环。
call :loop

echo loop finished

goto :eof

:loop
FOR /L %%I IN (1,1,10) DO (
    echo %%I
    IF %%I==5 exit /b
)

在这种情况下,“退出/ b”将退出“通话”并从“通话”后的行继续 所以输出是这样的:

1
2
3
4
5
loop finished