Я хочу сделать следующее из пакета Windows script:
start proc1.exe
start proc2.exe
...
start procN.exe
<wait for all N processes to complete> <-- What do I put here?
Как мне ждать завершения всех порожденных процессов?
Я хочу сделать следующее из пакета Windows script:
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
Команда sleep доступна в Windows Kit 2003 Resource Kit Tools. Если у вас этого нет, вы можете использовать ping на localhost, чтобы замедлить этот жесткий цикл.
Это можно сделать, если вы пишете код .NET или код Win32 C/С++ для запуска процессов, но нет способа сделать это в пакетном файле. Когда вы используете start
, чтобы make proc.exe выполнялся асинхронно, нет пакетной команды, которая позволяет вам вернуться позже и дождаться завершения.
Но вы можете сделать это легко на одном из языков сценариев, предназначенных для пакетной работы, Python, WSH и т.д.
Например, здесь простой script с использованием Windows script Host. WSH входит во все версии Windows с Windows 98. Таким образом, этот script должен работать где угодно.
Этот script запускает две программы и ждет их завершения. Сохраните его как 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 (строка используется для указания отдельных параметров для пакетного файла).
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
@call %AsyncParamBat% %AsyncParamCall%
@echo "Done at %DATE% %TIME%" > "%AsyncCountFilePrefix:"=%_%AsyncCountNum%_tmp_async_done.txt"