为什么这个批处理文件永远不会脱离循环?
For /L %%f In (1,1,1000000) Do @If Not Exist %%f Goto :EOF
Goto :EOF
不应该突破循环吗?
我想我应该更明确地询问...... 我怎样才能摆脱循环?
答案 0 :(得分:6)
基于Tim's second edit和this 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 expansion和call
子例程。
答案 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