Batch File Nested For /L Loops and Exiting them

青春壹個敷衍的年華 提交于 2019-12-10 10:34:08

问题


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

回答1:


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!