Waiting for Parallel batch scripts or command line

2020-02-15 06:11发布

问题:

I am finding it difficult to modify the script here to suit my requirements: https://stackoverflow.com/a/12665498/4683898

@echo off
setlocal
set "lock=%temp%\wait%random%.lock"

:: Launch one and two asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
start "" cmd /c 9>"%lock%1" one.bat
start "" cmd /c 9>"%lock%2" two.bat

:Wait for both scripts to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2) do (
  ( rem
  ) 9>"%lock%%%N" || goto :Wait
) 2>nul

::delete the lock files
del "%lock%*"

:: Launch three and four asynchronously
start "" cmd /c three.bat
start "" cmd /c four.bat

I am using a batch script, not to execute further batch scripts, but simply executing cmd commands (which run for a period of time) in parallel, and that works fine with the above script.

However, I want to be able to run more than just 2 commands/scripts, i.e. 3, 4, 5, (or whatever I desire) commands at a single time, running in parallel, let's call it, x.

So, I want to run x amount of cmd commands (that are executing in parallel), wait for them to terminate (using /c), and then executing the next bunch of x amount of cmd commands, and then the next bunch, etc, etc, until all cmd commands have executed.

How could I modify that script accordingly? (I have made a few attempts albeit with repeating errors "The process cannot access the file because it is being used by another process." in the initiating batch script; I presume this 'file' refers to the lock file.)

Thanks

EDIT:

@echo off
setlocal
set "lock=%temp%\wait%random%.lock"

call :a start cmd.exe /c somecommandA 1
call :a start cmd.exe /c somecommandB 2
call :wait
call :a start cmd.exe /c somecommandC 1
call :a start cmd.exe /c somecommandD 2
call :a start cmd.exe /c somecommandE 3

exit /b
:a
start "%~2" cmd /c 9>"%lock%%2" %1
exit /b
:wait
1>nul 2>nul ping /n 2 ::1
for %%N in (%lock%*) do (
  ( rem
  ) 9>"%%N" || goto :Wait
) 2>nul

回答1:

You can call the files easily with this script:

@echo off
setlocal
set "lock=%temp%\wait%random%.lock"


call :a one.bat 1
call :a two.bat 2
call :wait
call :a three.bat 1
call :a name.bat 2
call :a gfwagwa.bat 3


exit /b
:a
start "%~2" cmd /c 9>"%lock%%2" %1
exit /b
:wait
1>nul 2>nul ping /n 2 ::1
for %%N in (%lock%*) do (
  ( rem
  ) 9>"%%N" || goto :Wait
) 2>nul

call :wait simply replaces the waiting. Whenever you have called all files that are to be run asynchronously, call the wait function. Then you can call more scripts.

The second parameter is the number of the lock file. Make sure you don't have duplicate numbers before all those scripts using them are closed (i.e. before the next call :wait). Though you're not going to run out of numbers anyway, no reason to use duplicates.



回答2:

just to offer an alternative way:

@ECHO off
start "MyCommand-%~n0" cmd.exe /c ping localhost
start "MyCommand-%~n0" cmd.exe /c ipconfig /all
start "MyCommand-%~n0" cmd.exe /c sysinfo
:loop
tasklist /fi "windowtitle eq MyCommand-%~n0"  | find "===" >nul && goto :loop
echo finished!

Edit for your comment. bunch is the number of commands running in parallel.

@ECHO off
setlocal enabledelayedexpansion
set bunch=3

for /f "delims=:" %%a in ('findstr /n /b "REM ==" %~f0') do set /a datastart=%%a+1
set count=0
for /f "skip=%datastart% usebackq delims=" %%a in ("%~f0") do (
  set /a "count=(count+1) %% %bunch%"
  echo starting: %%a
  start "MyCommand-%~n0" cmd.exe /c %%a
  if !count!==0 echo waiting & call :loop
)
echo waiting & call :loop
echo finished!
goto :eof

:loop
tasklist /fi "windowtitle eq MyCommand-%~n0"  | find "===" >nul && goto :loop
goto :eof

REM == START DATA ==
ping localhost
ipconfig /all
systeminfo
tasklist
echo hello
schtasks /query
wmic bios get /value
timeout 10

the first for just gets the line number where your commands are (start of DATA section)