SETLOCAL ENABLEDELAYEDEXPANSION
set list=A B C D E
FOR %%a IN (%list%) DO (
start %%a.exe > ouput_%%a.txt
echo 120, 30 second loops = 60 min
FOR /L %%i IN (1,1,120) DO (
REM pause for 30 seconds
ping 1.1.1.1 -n 1 -w 30000 > nul
echo find the running executable
tasklist | findstr %%a.exe > nul
REM !ERRORLEVEL!
REM exit the script if no executable is found (i.e it has run successfully)
if !ERRORLEVEL! equ 1 goto success
)
REM kill executable if we haven't exited yet
taskkill /f /im %%a.exe
:success
)
This code doesn't go through the for loops as I expect them to. I tried to do something like this How to break inner loop in nested loop batch script , but to no avail. Any advice?
EDIT
ERRORLEVEL is not 1 when an executable has finished running.
SETLOCAL ENABLEDELAYEDEXPANSION
set list=A B C D E
FOR %%a IN (%LIST%) DO (
start %%a.exe > ouput_%%a.txt
REM 120, 30 second loops = 60 min
call :innerloop %%a
REM kill executable if we haven't exited yet
taskkill /f /im %%a.exe
)
goto :eof
:innerloop
FOR /L %%i IN (1,1,120) DO (
REM pause for 30 seconds
ping 1.1.1.1 -n 1 -w 30000 > nul
REM find the running executable
tasklist | findstr %%a.exe > nul
REM !ERRORLEVEL!
REM exit the script if no executable is found (i.e it has run successfully)
if %ERRORLEVEL% equ 1 goto :next
)
:next
goto :eof
Executing the goto
command within a for
loop breaks up the loop iteration. This is true for all nested for
loops.
However, what you can do is moving your inner for
loop into a sub-routine (call it using call
). This loop can be terminated by a goto
command, but after returning from the sub-routine, the remaining (outer) for
loop is not affected and continues iteration.
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
set list=A B C D E
FOR %%a IN (%list%) DO (
start %%a.exe > ouput_%%a.txt
echo 120, 30 second loops = 60 min
REM kill executable if we haven't exited yet
call :SUBLOOP %%a.exe && taskkill /f /im %%a.exe
)
exit /B
:SUBLOOP
FOR /L %%i IN (1,1,120) DO (
REM pause for 30 seconds
timeout /T 30 /NOBREAK > nul
echo find the running executable
tasklist | findstr /I /B "%~1" > nul
REM !ERRORLEVEL! is 0 if found and 1 otherwise
REM exit the script if no executable is found
REM (i.e it has run successfully)
if !ERRORLEVEL! equ 1 goto :EOF
)
exit /B 0
Herein I moved the inner for
loop into a sub-routine :SUBLOOP
, which is called from its former code section by call :SUBLOOP %%a.exe
, passing the current value to process (the executable %%a.exe
) from the outer for
loop to it. ERRORLEVEL
is transferred to the calling routine upon termination.
After returning from :SUBLOOP
back to the outer for
loop, it is checked whether or not ERRORLEVEL
is zero, and if so, the process of the currently iterated executable is killed. The &&
is a conditional command separator which executes the second command only if the first one succeeded, that is, if ERRORLEVEL
is cleared.
Note the exit /B
command after the outer for
loop which is necessary to not execute the SUBLOOP
section unintentionally after the outer loop has been completed.
Note:goto
does not terminate the for
loop iteration immediately; in fact every pending iteration is still counted silently, but no more commands of the for
body are executed. A loop with a huge number of iterations can therefore take a considerable amount of time before batch execution continues. Thank you @foxidrive for this useful information!
Moreover, if the goto
target label is placed within the for
body, execution continues at that point after total completion of the loop. Any code following that point is then treated as "normal" one not part of a for
body.
来源:https://stackoverflow.com/questions/32214744/batch-file-nested-for-l-loops-and-exiting-them