Exiting out of a FOR loop in a batch file?

Viewed 133657

Why does this batch file never break out of the loop?

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

Shouldn't the Goto :EOF break out of the loop?

Edit:

I guess I should've asked more explicitly... how can I break out of the loop?

9 Answers

you do not need a seperate batch file to exit a loop using exit /b if you are using call instead of goto like

call :loop

echo loop finished

goto :eof

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

in this case, the "exit /b" will exit the 'call' and continue from the line after 'call' So the output is this:

1
2
3
4
5
loop finished

My answer
Use nested for loops to provide break points to the for /l loop.

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

Explanation The code must be tweaked significantly to properly use the nested loops. For example, what is written will have leading zeros.
"Regular" for loops can be immediately broken out of with a simple goto command, where for /l loops cannot. This code's innermost for /l loop cannot be immediately broken, but an overall break point is present after every 10 iterations (as written). The innermost loop doesn't have to be 10 iterations -- you'll just have to account for the math properly if you choose to do 100 or 1000 or 2873 for that matter (if math even matters to the loop).

History I found this question while trying to figure out why a certain script was running slowly. It turns out I used multiple loops with a traditional loop structure:

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

This script file had become somewhat long and it was being run from a network drive. This type of loop file was called maybe 20 times and each time it would loop 50-100 times. The script file was taking too long to run. I had the bright idea of attempting to convert it to a for /l loop. The number of needed iterations is unknown, but less than 10000. My first attempt was this:

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

With echo on, I quickly found out that the for /l loop still did ... something ... without actually doing anything. It ran much faster, but still slower than I thought it could/should. Therefore I found this question and ended up with the nested loop idea presented above.

Side note It turns out that the for /l loop can be sped up quite a bit by simply making sure it doesn't have any output. I was able to do this for a noticeable speed increase:

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

It is impossible to get out of a FOR /L before it completes all iterations.

I have debugged the execution of a FOR /L by the cmd.exe process.

Microsoft could document it better and save us all this effort.

Facts:

  1. The loop is a simple while (TRUE) and the break only happens when the iteration limit is reached.
  2. When an EXIT /b or a GOTO is encountered, no more commands are executed until the end of the iterations.
  3. When an EXIT is encountered, the cmd.exe process is terminated.

Tests:

12 seconds

FOR /L %%G in (1,1,5000000) do (ECHO Only once & GOTO :EOF)

7 seconds

FOR /L %%G in (1,1,5000000) do (ECHO Only once & EXIT /b)

0 seconds, but this terminates the cmd.exe process

FOR /L %%G in (1,1,5000000) do (ECHO Only once & EXIT)
Related