windows batch-file command-line cmd call

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! :)



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)