如何在退出之前等待所有批处理文件完成?

rox*_*sap 6 windows command-line cmd batch-file call

我有一个主批处理文件,而不是调用其他4个批处理文件,所以我们可以并行运行.

例:

Main.bat

    start call batch1.bat
    start call batch2.bat
    start call batch3.bat
    start call batch4.bat

    exit
Run Code Online (Sandbox Code Playgroud)

我希望Main.bat在所有batch1到batch 4停止执行后退出.通过这种方式,我可以获得批处理文件的总运行时间.问题是Main.bat甚至在batch1到batch4完成执行之前退出.

我尝试为每个批处理文件计算%errorlevel%,但即使4个.bat文件仍在运行,它总是返回0.

希望有人可以帮助我!

谢谢!:)

Aac*_*ini 14

我认为这是最简单,最有效的方式:

@echo off

echo %time%

(
    start call batch1.bat
    start call batch2.bat
    start call batch3.bat
    start call batch4.bat
) | set /P "="

echo %time%
Run Code Online (Sandbox Code Playgroud)

在此方法中,主文件中的等待状态是事件驱动的,因此它不消耗任何CPU时间!

编辑:添加了一些解释

set /P( block )输出中的start任何命令都行时,该命令将终止,但命令不会在此cmd.exe中显示任何行.这样,set /Pstart命令启动的所有进程结束之前,一直等待输入.此时,与之关联的管道( block )关闭,因此set /PStdin关闭,set /P操作系统终止命令.

  • `set /P` 在 cmd 的另一个实例中运行,该实例的 `StandardInput` 设置为管道。块中的每个“start”也会生成一个 cmd 实例。但由于“start”创建了一个新控制台(如果未使用 /B),Windows 会使用附加控制台屏幕缓冲区的句柄替换块中每个 cmd 实例上的管道“StandardOutput”。但它们仍然继承了管道的句柄,因此当“set /P”在其一端调用“ReadFile”时,仍然存在潜在的写入者和读取块,直到具有另一端句柄的所有 cmd 实例都退出为止。 (2认同)
  • 父进程只需将“CREATE_NEW_CONSOLE”标志传递给“CreateProcess”。子进程看到它被标记为创建一个新控制台,因此 kernelbase 中的启动代码会生成一个 conhost.exe 实例(通过 IOCTL 到“ConDrv”)。子级是使用继承的管道作为其“StandardOutput”创建的(请使用设置为在“ntdll!RtlUserThreadStart”提前中断的调试器查看此内容),但附加到新控制台会覆盖其现有的标准句柄。它仍然具有继承的管道句柄;但是,如果不知道句柄值(4 的倍数,例如 68),它就无法对其执行任何操作。 (2认同)
  • Windows 8 及更高版本使用 condrv.sys 设备驱动程序而不是 LPC。现在控制台句柄作为虚拟文件打开,例如“\Device\ConDrv\Input”和“\Device\ConDrv\Output”。这些句柄是内核文件对象的普通句柄(4 的倍数),并且使用常规 NT I/O 函数,例如“NtCreateFile”、“NtClose”、“NtReadFile”、“NtWriteFile”和“NtDeviceIoControlFile”。老式 DOS 设备实现为 `CON` => `Device\ConDrv\Console`、`CONIN$` => `\Device\ConDrv\CurrentIn` 和 `CONOUT$` => `\Device\ConDrv\当前输出`。 (2认同)

Squ*_*man 6

尝试一下。

@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
Run Code Online (Sandbox Code Playgroud)

  • 是的,并行运行是因为管道“|”,而不是因为“start”命令! (3认同)

Ste*_*han 5

为新进程提供一个唯一的标题字符串,然后检查标题中是否带有该字符串的任何进程正在运行:

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
Run Code Online (Sandbox Code Playgroud)

find用于,因为tasklist不会返回有用的错误级别)