如何在退出前等待所有批处理文件完成?
How to wait all batch files to finish before exiting?
我有一个主批处理文件而不是调用其他 4 个批处理文件,因此我们可以 运行 并行。
示例:
Main.bat
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
exit
我希望 Main.bat 在所有批处理 1 到批处理 4 停止执行后退出。这样我就可以得到批处理文件的总时间运行。问题是 Main.bat 甚至在 batch1 到 batch4 完成执行之前就退出了。
我尝试为每个批处理文件计算 %errorlevel%,但它总是 return 0,即使 4 个 .bat 文件仍然是 运行ning。
希望有人能帮助我!
谢谢! :)
您可以让 batch1..batchn4 在它们完成后创建标志文件 运行。
例如 echo y > flag1
在 batch1.bat
然后在主批处理文件中检查标志文件是否存在,然后退出。您需要某种睡眠实用程序来在主批处理文件的末尾执行类似的操作:
IF EXIST flag1 GOTO check2
sleep <for a short amount of time>
goto check1
:check2
IF EXIST flag2 GOTO check3
sleep <for a short amount of time>
goto check2
:check3
IF EXIST flag3 GOTO check4
sleep <for a short amount of time>
goto check3
:check4
IF EXIST flag4 GOTO xit
sleep <for a short amount of time>
goto check4
:xit
这种技术的缺点是您的计时会稍微偏离,因为您正在轮询标志文件而不是事件驱动。在您的情况下,这可能是问题,也可能不是问题。批处理文件以这种方式非常有限。您最好尝试使用 PowerShell 或 python 或其他一些功能更强大的脚本语言。
给新进程一个唯一的标题字符串,然后检查标题中有这个字符串的进程是否是运行:
start "+++batch+++" batch1.bat
start "+++batch+++" batch2.bat
start "+++batch+++" batch3.bat
start "+++batch+++" batch4.bat
:loop
timeout /t 1 >nul
tasklist /fi "windowtitle eq +++batch+++*" |find "cmd.exe" >nul && goto :loop
echo all tasks finished
(使用 find
,因为 tasklist
没有 return 有用的错误级别)
试试这个。
@echo off
echo %time%
start "" /wait cmd /c bat1.bat |start "" /wait cmd /c bat2.bat |start "" /wait cmd /c bat3.bat
echo %time%
pause
我认为这是最简单高效的方式:
@echo off
echo %time%
(
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
) | set /P "="
echo %time%
在这个方法中,主文件中的等待状态是事件驱动,所以它不会消耗任何CPU时间!
编辑:添加了一些解释
当 ( block )
中的任何命令输出一行时,set /P
命令将终止,但 start
命令不显示任何行 cmd.exe。这样,set /P
一直等待输入,直到所有由 start
命令启动的进程结束。此时与 ( block )
关联的管道关闭,因此 set /P
Stdin 关闭并且 set /P
命令由 OS.
终止
没有人提到这个解决方案,我认为这是最好的。将它放在脚本的末尾,如果需要修改进程名称和搜索字符串。
这也包括远程工作所需的修改,这很让人头疼。最初我使用任务列表而不是 WMIC 并检查了调用 START 时定义的命名 window 标题,但是 windowName 在远程使用时在任务列表中是 N/A。在我们的情况下,powershell 命令比超时更有效,这要求我们从 Jenkins 代理中 运行。
:WAIT_FOR_FINISH
ECHO Waiting...
powershell -command "Start-Sleep -Milliseconds 5000" > nul
WMIC PROCESS WHERE Name="cmd.exe" GET commandline | findstr "searchString1 searchString 2" > nul && goto :WAIT_FOR_FINISH
ECHO.
ECHO Processes are Complete!
ECHO.
我有一个主批处理文件而不是调用其他 4 个批处理文件,因此我们可以 运行 并行。
示例:
Main.bat
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
exit
我希望 Main.bat 在所有批处理 1 到批处理 4 停止执行后退出。这样我就可以得到批处理文件的总时间运行。问题是 Main.bat 甚至在 batch1 到 batch4 完成执行之前就退出了。
我尝试为每个批处理文件计算 %errorlevel%,但它总是 return 0,即使 4 个 .bat 文件仍然是 运行ning。
希望有人能帮助我!
谢谢! :)
您可以让 batch1..batchn4 在它们完成后创建标志文件 运行。
例如 echo y > flag1
在 batch1.bat
然后在主批处理文件中检查标志文件是否存在,然后退出。您需要某种睡眠实用程序来在主批处理文件的末尾执行类似的操作:
IF EXIST flag1 GOTO check2
sleep <for a short amount of time>
goto check1
:check2
IF EXIST flag2 GOTO check3
sleep <for a short amount of time>
goto check2
:check3
IF EXIST flag3 GOTO check4
sleep <for a short amount of time>
goto check3
:check4
IF EXIST flag4 GOTO xit
sleep <for a short amount of time>
goto check4
:xit
这种技术的缺点是您的计时会稍微偏离,因为您正在轮询标志文件而不是事件驱动。在您的情况下,这可能是问题,也可能不是问题。批处理文件以这种方式非常有限。您最好尝试使用 PowerShell 或 python 或其他一些功能更强大的脚本语言。
给新进程一个唯一的标题字符串,然后检查标题中有这个字符串的进程是否是运行:
start "+++batch+++" batch1.bat
start "+++batch+++" batch2.bat
start "+++batch+++" batch3.bat
start "+++batch+++" batch4.bat
:loop
timeout /t 1 >nul
tasklist /fi "windowtitle eq +++batch+++*" |find "cmd.exe" >nul && goto :loop
echo all tasks finished
(使用 find
,因为 tasklist
没有 return 有用的错误级别)
试试这个。
@echo off
echo %time%
start "" /wait cmd /c bat1.bat |start "" /wait cmd /c bat2.bat |start "" /wait cmd /c bat3.bat
echo %time%
pause
我认为这是最简单高效的方式:
@echo off
echo %time%
(
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
) | set /P "="
echo %time%
在这个方法中,主文件中的等待状态是事件驱动,所以它不会消耗任何CPU时间!
编辑:添加了一些解释
当 ( block )
中的任何命令输出一行时,set /P
命令将终止,但 start
命令不显示任何行 cmd.exe。这样,set /P
一直等待输入,直到所有由 start
命令启动的进程结束。此时与 ( block )
关联的管道关闭,因此 set /P
Stdin 关闭并且 set /P
命令由 OS.
没有人提到这个解决方案,我认为这是最好的。将它放在脚本的末尾,如果需要修改进程名称和搜索字符串。
这也包括远程工作所需的修改,这很让人头疼。最初我使用任务列表而不是 WMIC 并检查了调用 START 时定义的命名 window 标题,但是 windowName 在远程使用时在任务列表中是 N/A。在我们的情况下,powershell 命令比超时更有效,这要求我们从 Jenkins 代理中 运行。
:WAIT_FOR_FINISH
ECHO Waiting...
powershell -command "Start-Sleep -Milliseconds 5000" > nul
WMIC PROCESS WHERE Name="cmd.exe" GET commandline | findstr "searchString1 searchString 2" > nul && goto :WAIT_FOR_FINISH
ECHO.
ECHO Processes are Complete!
ECHO.