如何从Windowsshell产生几个进程并等待它们全部完成?

我想从Windows批处理脚本执行以下操作:

start proc1.exe start proc2.exe ... start procN.exe <wait for all N processes to complete> <-- What do I put here? 

我如何等待所有产生的过程完成?

这很丑陋,但是可以将每个命令包装在运行命令的另一个批处理文件中,然后发出命令已完成的信号。 您的主批处理文件将异步调用这些批处理文件中的每一个,并且在一个循环中等待信号。

例如:

main.bat

 start cmd /c proc1.bat start cmd /c proc2.bat :wait sleep 1 IF NOT EXIST proc1done GOTO wait IF NOT EXIST proc2done GOTO wait del proc1done del proc2done echo All processes are complete 

proc1.bat

 proc1.exe echo Done > proc1done 

睡眠命令在Windows server 2003资源工具包工具中可用。 如果你没有这个,你可以在localhost上使用一个ping命令来减慢这个紧密的循环。

如果您编写.NET代码或Win32 C / C ++代码来启动进程,则可以这样做,但在批处理文件中无法执行此操作。 一旦使用start使proc1.exe异步运行,就没有批处理命令可以让你稍后再回来等待它完成。

但是,您可以使用为批处理,Python, WSH等设计的脚本语言之一轻松完成此操作。

例如,以下是使用Windows Script Host的简单脚本 。 自Windows 98以来,WSH包含在所有版本的Windows中。 所以这个脚本应该可以运行

这个脚本启动两个程序并等待它们完成。 将其另存为start2.wsf 。 然后在批处理文件中使用它:

 start2.wsf "prog1.exe" "prog2.exe" <package> <job id="Start 2 Procs"> <runtime> <description>Start 2 programs and wait for them both to finish. </description> <unnamed name="program" helpstring="the program to run" many="false" required="2" /> <example> Example: Start2.wsf "cl -c foo.obj" "cl -c bar.obj" </example> </runtime> <script language="JScript"> if (WScript.Arguments.length < 2) { WScript.Arguments.ShowUsage(); WScript.Quit(); } var proc1 = WScript.Arguments.Unnamed.Item(0); var proc2 = WScript.Arguments.Unnamed.Item(1); var Shell = WScript.CreateObject("WScript.Shell"); var oProc1 = Shell.Exec(proc1); var oProc2 = Shell.Exec(proc2); while (oProc1.Status == 0 && oProc2.Status == 0) { WScript.Sleep(1000); } </script> </job> </package> 

通常情况下,你可以使用Python来做这样的事情,但是在这里(受到这篇文章和其他人的启发):

 calcFromList.bat < DesiredBatchFile > < TxtFile > [--async [SleepTimeBetweenSpawns]] 

它将为TxtFile中的每一行生成一个进程(该行用于指定批处理文件的各个参数)。

calcFromList.bat:

 echo off pushd \ %~d0 cd "%~dp0" set CALL_BAT="%~1" set FILE_CONTAINING_LIST="%~2" if %CALL_BAT%=="" (goto badval) if %FILE_CONTAINING_LIST%=="" (goto badval2) if "%3"=="--async" goto async for /f "delims=¬" %%X in ('type %FILE_CONTAINING_LIST%') do (call %CALL_BAT% %%X) goto end :async set /a AsyncCountNum=1 set SLEEP_VALUE_S=0 if not "%4"=="" (set SLEEP_VALUE_S=%4) set AsyncParamBat=%CALL_BAT% :: Find unique id even if called simultaneously (using simple collision detection) :newid timeout /t 1 /nobreak > NUL set AsyncRand=%RANDOM:~-1%%RANDOM:~-2%%RANDOM:~-3% set AsyncCountFilePrefix="%FILE_CONTAINING_LIST:"=%__%AsyncRand%" set AsyncCollisionText="%~1;%~2;%~3;%~4;" IF EXIST "%AsyncCountFilePrefix:"=%0" GOTO newid echo %AsyncCollisionText% > "%AsyncCountFilePrefix:"=%_init_async_done.txt" set /p AsyncCheckColision=<"%AsyncCountFilePrefix:"=%_init_async_done.txt" if "%AsyncCollisionText:"=% "=="%AsyncCheckColision:"=%" GOTO idfound timeout /t 1 /nobreak > NUL GOTO newid :idfound echo Beginning spawning of processes (id = %AsyncRand%)... for /f "delims=¬" %%X in ('type %FILE_CONTAINING_LIST%') do (set AsyncParamCall="%%~X" & start "Batch (from id %AsyncRand%)" /D "%~dp0" "cmd /c asyncExec.bat" & set /a AsyncCountNum+=1 & timeout /t %SLEEP_VALUE_S% /nobreak > NUL) set /a AsyncCountNum-=1 echo All %AsyncCountNum% processes spawned, waiting for their completion... :wait timeout /t 2 /nobreak > NUL for /l %%x in (1, 1, %AsyncCountNum%) do (IF NOT EXIST "%AsyncCountFilePrefix:"=%_%%x_tmp_async_done.txt" GOTO wait ) echo Finished, cleaning up... for /l %%x in (1, 1, %AsyncCountNum%) do (del /F /Q "%AsyncCountFilePrefix:"=%_%%x_tmp_async_done.txt") del /F /Q "%AsyncCountFilePrefix:"=%_init_async_done.txt" goto end start "Calib for %~TARGET_FOLDER%" /D "%~dp0" "cmd /k calibCamsSequence.bat" goto end :badval echo No bat file specified! (first parameter) goto end :badval2 echo No list file specified! (second parameter) :end popd 

asyncExec.bat:

 @call %AsyncParamBat% %AsyncParamCall% @echo "Done at %DATE% %TIME%" > "%AsyncCountFilePrefix:"=%_%AsyncCountNum%_tmp_async_done.txt"