windows - ¿Cómo esperar a que finalicen todos los archivos por lotes antes de salir?
batch-file command-line (6)
Tengo un archivo por lotes principal que llama a otros 4 archivos por lotes para que podamos ejecutarlos en paralelo.
Ejemplo:
Main.bat
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
exit
Quiero que Main.bat salga después de que todo el lote1 al lote 4 haya dejado de ejecutarse. De esta manera, puedo obtener el tiempo de ejecución total del archivo por lotes. El problema es que Main.bat sale incluso antes de que el lote1 al lote4 termine de ejecutarse.
Intenté calcular para% errorlevel% para cada archivo por lotes, pero siempre devuelve 0 aunque los 4 archivos .bat todavía se están ejecutando.
¡Esperando que alguien pueda ayudarme!
¡Gracias! :)
Considere la serie de comandos ''Job'' en Powershell como una alternativa al uso de un script por lotes.
Creo que esta es la forma más simple y eficiente:
@echo off
echo %time%
(
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
) | set /P "="
echo %time%
En este método, el estado de espera en el archivo principal está controlado por eventos , por lo que no consume tiempo de CPU.
EDITAR : se agregaron algunas explicaciones
El comando
set /P
finalizaría cuando cualquiera de los comandos en el
( block )
genera una línea, pero los comandos de
start
no muestran ninguna línea
en este cmd.exe
.
De esta manera,
set /P
sigue esperando la entrada hasta que finalicen todos los procesos iniciados por los comandos de
start
.
En ese punto, la línea de tubería asociada al
( block )
está cerrada, por lo que el
set /P
operativo
set /P
está cerrado y el sistema operativo termina el comando
set /P
Nadie mencionó esta solución, que considero la mejor. Ponga esto al final de su script, modifique el nombre de su proceso si es necesario y las cadenas de búsqueda.
Esto incluye las modificaciones necesarias para que este trabajo también sea remoto, lo que fue un dolor de cabeza. Originalmente utilicé la lista de tareas en lugar de WMIC y verifiqué los títulos de las ventanas con nombre definidos cuando se llama a START, pero windowName es N / A en la lista de tareas cuando se usa de forma remota. El comando powershell funcionó mejor que el tiempo de espera en nuestras circunstancias, lo que nos obligó a ejecutar esto desde un agente de 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.
Podría hacer que batch1..batchn4 cree archivos de marca cuando terminen de ejecutarse.
Por ejemplo,
echo y > flag1
en batch1.bat
Luego, en el archivo por lotes principal, verifique la existencia de los archivos de marca antes de salir. Necesitaría algún tipo de utilidad de suspensión para hacer algo como esto al final del archivo principal por lotes:
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
La desventaja de esta técnica es que su tiempo se va a retrasar un poco porque está sondeando los archivos de marca en lugar de estar controlado por eventos. Esto puede o no ser un problema en su situación. Los archivos por lotes son bastante limitados de esta manera. Es mejor que intentes hacerlo en PowerShell o Python o en algún otro lenguaje de programación más capaz.
Prueba esto.
@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
asigne una cadena de título única a los nuevos procesos, luego verifique si se están ejecutando procesos con esta cadena en el título:
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
(se utiliza
find
, porque la
tasklist
no devuelve un nivel de error útil)