批处理文件嵌套/ L循环并退出它们 [英] Batch File Nested For /L Loops and Exiting them

查看:169
本文介绍了批处理文件嵌套/ L循环并退出它们的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  SETLOCAL ENABLEDELAYEDEXPANSION 
set list = ABCDE

FOR %% a IN(%list%)DO(
start %% a .exe> ouput _ %% a.txt
echo 120,30 second loop = 60 min
FOR / L %% i IN(1,1,120)DO(
REM暂停30秒
ping 1.1.1.1 -n 1 -w 30000> nul

echo找到正在运行的可执行文件
tasklist | findstr %% a.exe> nul
REM !ERRORLEVEL!
如果没有找到可执行文件,REM退出脚本(即它已经成功运行)
if!ERRORLEVEL!equ 1 goto success

REM 't已退出
taskkill / f / im %% a.exe
:success

这段代码并没有像我期望的那样通过for循环。我试图做这样的事情如何如何打破内部循环在嵌套循环批处理脚本,但无济于事。任何建议?
$ b

编辑

当可执行文件完成时,ERRORLEVEL不是1运行。

  SETLOCAL ENABLEDELAYEDEXPANSION 
set list = ABCDE

FOR %% IN(%LIST %)DO(
start %% a.exe>输出_ %% a.txt
REM 120,30秒循环= 60分钟
调用:innerloop %% a
REM杀死可执行文件,如果我们还没有退出
taskkill / f / im %% a.exe

goto:eof
:innerloop
FOR / L %%我IN(1,1,120)DO(
REM暂停30秒
ping 1.1.1.1 -n 1 -w 30000> nul

REM找到正在运行的可执行文件
任务列表| findstr %% a.exe> nul
REM!ERRORLEVEL!
如果找不到可执行文件,REM将退出脚本(即已成功运行)
如果%ERRORLEVEL% 1 goto:next

:next
goto:eof


c>在中为循环执行 goto 命令会破坏循环迭代。对于全部嵌套 for 循环。



然而,你可以做什么将循环内部的循环移动到一个子例程中(使用 call 调用它)。这个循环可以由 goto 命令结束,但是在从子例程返回之后,剩下的(外部的)代表循环不受影响,并继续迭代。

  @ECHO OFF 
SETLOCAL ENABLEDELAYEDEXPANSION
set list = ABCDE

FOR %% a IN(%list%)DO(
start %% a.exe>输出_ %% a.txt
回显120,30秒循环= 60 min
如果我们还没有退出,则可以杀死可执行文件
call:SUBLOOP %% a.exe&& taskkill / f / im %% a.exe

退出/ B

:SUBLOOP
FOR / L %% i IN(1,1,120)DO(
REM暂停30秒
超时/ T 30 / NOBREAK > nul
echo找到正在运行的可执行文件
tasklist | findstr / I / B%〜1> nul
REM!ERRORLEVEL!为0,否则为1
如果找不到可执行文件,REM退出脚本
REM(即它已经成功运行)
if!ERRORLEVEL!equ 1 goto:EOF

exit / B 0

这里我把循环的内部移到了一个子程序中:SUBLOOP ,它从前面的代码段调用调用:SUBLOOP %% a.exe ,将当前值传递给进程(可执行文件 %% a.exe )从外部循环。 ERRORLEVEL 在终止时被传送到调用例程。

:SUBLOOP 返回在循环的外部中,检查 ERRORLEVEL 是否为零,如果是,则检查当前进程迭代的可执行文件被终止。 && 是一个条件命令分隔符,它只有在第一个命令成功的时候才执行第二个命令,也就是说,如果 ERRORLEVEL 被清除。

在循环的外部之后,注意出口/ B 这是在外循环完成后无意执行 SUBLOOP 部分所必需的。



注意:
goto 不立即终止循环迭代的;实际上,每个挂起的迭代仍然被默默地计算在内,但是没有更多的 for body命令被执行。因此,在批处理执行继续之前,具有大量迭代的循环可能需要相当长的时间。谢谢@foxidrive这个有用的信息
a>!


此外,如果 goto 目标标签位于 for 主体内,执行循环完成后,继续执行。之后的任何代码将被视为正常,而不是 body的部分。


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.

这篇关于批处理文件嵌套/ L循环并退出它们的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆