How to run multiple .BAT files within a .BAT file
Asked Answered
S

18

868

I'm trying to get my commit-build.bat to execute other .BAT files as part of our build process.

Content of commit-build.bat:

"msbuild.bat"
"unit-tests.bat"
"deploy.bat"

This seems simple enough, but commit-build.bat only executes the first item in the list (msbuild.bat).

I have run each of the files separately with no problems.

Swithin answered 9/7, 2009 at 13:47 Comment(2)
@sean - You don't have to install the full Cygwin package to get command line utils to work. Just take all the cygwin dlls out of the package place them in a pathed directory, put all your tools in another pathed directory and you're good to go.Isauraisbel
presuming that each of these files are only batch why not just put them in one large file and use the timeout function to allow each time to start.Homologous
M
1457

Use:

call msbuild.bat
call unit-tests.bat
call deploy.bat

When not using CALL, the current batch file stops and the called batch file starts executing. It's a peculiar behavior dating back to the early MS-DOS days.

Maje answered 9/7, 2009 at 13:48 Comment(9)
weird , i've tried without the "call" on windows 7 and i remember that it worked , but on windows xp it required this command. could it be?Agitprop
Without call, per the original DOS spec, should do command chaining and NOT return. A popular option back before "CALL" was added was to open a child command prompt like "command /c second.bat" as that will return as well.Airlie
I had the problem on Windows 7 entreprise so it's not only xpLepidus
On Windows 10 only the first line gets executed. The answer by farheen however worked.Genuine
How to pass parameters to the batch files, and one of the param is a path with spaces.Araceli
use "call myfile.bat param1 param2 param3", in bat file you can get the param1 by %1, and so on (only %1 through %9)Apathetic
I'm using Windows 10 and this works like a charm for me.Entomophagous
Does it hold true evenif the child .cmd file calls poweshell script? for me somehow it doesnt work and always quits after the first .cmd is finished. I am using windows 10Bland
use lowercase call. In my case (windows 11) uppercase CALL did not work and did not return any errors either. Thanks Microsoft - One more time.Elwin
C
204

All the other answers are correct: use call. For example:

 call "msbuild.bat"

History

In ancient DOS versions it was not possible to recursively execute batch files. Then the call command was introduced that called another cmd shell to execute the batch file and returned execution back to the calling cmd shell when finished.

Obviously in later versions no other cmd shell was necessary anymore.

In the early days many batch files depended on the fact that calling a batch file would not return to the calling batch file. Changing that behaviour without additional syntax would have broken many systems like batch menu systems (using batch files for menu structures).

As in many cases with Microsoft, backward compatibility therefore is the reason for this behaviour.

Tips

If your batch files have spaces in their names, use quotes around the name:

call "unit tests.bat"

By the way: if you do not have all the names of the batch files, you could also use for to do this (it does not guarantee the correct order of batch file calls; it follows the order of the file system):

FOR %x IN (*.bat) DO call "%x"

You can also react on errorlevels after a call. Use:

exit /B 1   # Or any other integer value in 0..255

to give back an errorlevel. 0 denotes correct execution. In the calling batch file you can react using

if errorlevel neq 0 <batch command>

Use if errorlevel 1 if you have an older Windows than NT4/2000/XP to catch all errorlevels 1 and greater.

To control the flow of a batch file, there is goto :-(

if errorlevel 2 goto label2
if errorlevel 1 goto label1
...
:label1
...
:label2
...

As others pointed out: have a look at build systems to replace batch files.

Chenoweth answered 9/7, 2009 at 14:2 Comment(5)
agreed, but the loop could, in this case, process the files in the wrong (alphabetical?) orderVidette
Nice and very complete answer. If you're including control flow, it might be good to note that instead of goto, you can do subroutines by using call :label1 , and the 'return' statement in batch files is the slightly strange goto :eof (and no need to make an eof label yourself, that exists by default).Reputation
the errorlevel command example gave me a problem on Windows 10 (in the cmd console). I modified the command simply to be if errorlevel neq echo Houston We have a Problem!. My batch process had no problems and completed mostly normally, but every step of the way where I used this command after a call statement, I got "neq was unexpected at this time". Thinking they may have changed the not-equal syntax, I tried != and also <> but kept getting the same "not expected at this time" error for the new syntax. what could I be doing wrong?Perkins
TWMP Use neq 0 instead.Noggin
Thanks for giving the historical perspective. Initially when I encountered this bevaiour it seemed completely bizzare.Cussed
B
159

If we want to open multiple command prompts then we could use

start cmd /k

/k: is compulsory which will execute.

Launching many command prompts can be done as below.

start cmd /k Call rc_hub.bat 4444

start cmd /k Call rc_grid1.bat 5555

start cmd /k Call rc_grid1.bat 6666

start cmd /k Call rc_grid1.bat 5570.
Bioscope answered 27/8, 2012 at 5:17 Comment(12)
that is what we were searching for, as our first app blocks the console, thanks for the hintState
this will run multiple instances of command and will even work for running multiple batch files that have <pause>. +1 as this is exactly the solution i was looking for!Seductive
could you please explain that those numbers are in your answer? Their purpose its not clear.Bonucci
Note that most people probably want to use start "Window title" /wait cmd /k call something.bat in order to run things in sequential order.Cyanosis
(or start "Window title" /wait cmd /c something.bat, where cmd /c closes the window once finished)Cyanosis
This is the best answer, as the 'call' solution don't work in Windows10Kerikeriann
this should be the correct answer. It's the only one that work around blocking issues.Lazaro
Thank you, that what I was looking for, but I would like to mention that you have to specify the full path of the batch file, for example: start cmd /k Call C:\Batches\rc_hub.batWellappointed
If we set some environment variables in the first .bat file using set not setx, will the context be continued into the second command? Is the context according to parent command prompt or the children bat files.Rabble
Why not just start <batch_file.bat> Eg: start rc_hub.bat 4444 start rc_grid1.bat 5555 start rc_grid1.bat 6666 start rc_grid1.bat 5570Afghani
@Bioscope Thanks :) that is the answer, I was looking for running all microservices on different cmd at the same timeInlay
As per the above comments, this works whereas "call" (either using a FOR loop or specifying each bat file) doesn't work, at least in Windows 10. Only the first bat file is called.Curia
D
44

Try:

call msbuild.bat
call unit-tests.bat
call deploy.bat
Dished answered 9/7, 2009 at 13:49 Comment(0)
E
34

using "&"

As you have noticed executing the bat directly without CALL,START, CMD /C causes to enter and execute the first file and then the process to stop as the first file is finished. Though you still can use & which will be the same as using command1 & command2 directly in the console:

(
    first.bat
)&(
    second.bat
)& (
    third.bat
)&(
    echo other commands
)

In a term of machine resources this will be the most efficient way though in the last block you won't be able to use command line GOTO,SHIFT,SETLOCAL.. and its capabilities will almost the same as in executing commands in the command prompt. And you won't be able to execute other command after the last closing bracket

Using CALL

call first.bat
call second.bat
call third.bat

In most of the cases it will be best approach - it does not create a separate process but has almost identical behaviour as calling a :label as subroutine. In MS terminology it creates a new "batch file context and pass control to the statement after the specified label. The first time the end of the batch file is encountered (that is, after jumping to the label), control returns to the statement after the call statement."

You can use variables set in the called files (if they are not set in a SETLOCAL block), you can access directly labels in the called file.

CMD /C, Pipes ,FOR /F

Other native option is to use CMD /C (the /C switch will force the called console to exit and return the control) Something that cmd.exe is doing in non transparent way with using FOR /F against bat file or when pipes are used. This will spawn a child process that will have all the environment ot the calling bat. Less efficient in terms of resources but as the process is separate ,parsing crashes or calling an EXIT command will not stop the calling .bat

@echo off
CMD /c first.bat
CMD /C second.bat

::not so different than the above lines.
:: MORE,FINDSTR,FIND command will be able to read the piped data 
:: passed from the left side

break|third.bat

START

Allows you more flexibility as the capability to start the scripts in separate window , to not wait them to finish, setting a title and so on. By default it starts the .bat and .cmd scripts with CMD /K which means that the spawned scripts will not close automatically.Again passes all the environment to the started scripts and consumes more resources than cmd /c:

:: will be executed in the same console window and will wait to finish
start "" /b /w cmd /c first.bat 

::will start in a separate console window and WONT wait to be finished
:: the second console window wont close automatically so second.bat might need explicit exit command
start "" second.bat

::Will start it in a separate window ,but will wait to finish
:: closing the second window will cause Y/N prompt
:: in the original window 
start "" /w third.cmd


::will start it in the same console window
:: but wont wait to finish. May lead to a little bit confusing output
start "" /b cmd /c fourth.bat

WMIC

Unlike the other methods from now on the examples will use external of the CMD.exe utilities (still available on Windows by default). WMIC utility will create completely separate process so you wont be able directly to wait to finish. Though the best feature of WMIC is that it returns the id of the spawned process:

:: will create a separate process with cmd.exe /c
WMIC process call create "%cd%\first.bat","%cd%"

::you can get the PID and monitoring it with other tools
for /f "tokens=2 delims=;= " %%# in ('WMIC process call create "%cd%\second.bat"^,"%cd%" ^|find "ProcessId"') do (
    set "PID=%%#"
)
echo %PID%

You can also use it to start a process on a remote machine , with different user and so on.

SCHTASKS

Using SCHTASKS provides some features as (obvious) scheduling , running as another user (even the system user) , remote machine start and so on. Again starts it in completely separate environment (i.e. its own variables) and even a hidden process, xml file with command parameters and so on :

SCHTASKS /create /tn BatRunner /tr "%cd%\first.bat" /sc ONCE /sd 01/01/1910 /st 00:00
SCHTASKS /Run /TN BatRunner
SCHTASKS /Delete /TN BatRunner /F

Here the PID also can acquired from the event log.

ScriptRunner

Offers some timeout between started scripts. Basic transaction capabilities (i.e. rollback on error) and the parameters can be put in a separate XML file.

::if the script is not finished after 15 seconds (i.e. ends with pause) it will be killed
ScriptRunner.exe -appvscript %cd%\first.bat -appvscriptrunnerparameters -wait -timeout=15


::will wait or the first called script before to start the second
:: if any of the scripts exit with errorcode different than 0 will try
:: try to restore the system in the original state
ScriptRunner.exe -appvscript second.cmd arg1 arg2 -appvscriptrunnerparameters -wait -rollbackonerror -appvscript third.bat -appvscriptrunnerparameters -wait -timeout=30 -rollbackonerror
Engleman answered 6/11, 2020 at 19:30 Comment(0)
C
32

If we have two batch scripts, aaa.bat and bbb.bat, and call like below

call aaa.bat
call bbb.bat

When executing the script, it will call aaa.bat first, wait for the thread of aaa.bat terminate, and call bbb.bat.

But if you don't want to wait for aaa.bat to terminate to call bbb.bat, try to use the START command:

START ["title"] [/D path] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED]
  [/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL]
  [/AFFINITY <hex affinity>] [/WAIT] [/B] [command/program]
  [parameters]

Exam:

start /b aaa.bat
start /b bbb.bat
Cynthia answered 29/10, 2013 at 16:31 Comment(0)
C
30

You are calling multiple batches in an effort to compile a program. I take for granted that if an error occurs:
1) The program within the batch will exit with an errorlevel;
2) You want to know about it.

for %%b in ("msbuild.bat" "unit-tests.bat" "deploy.bat") do call %%b|| exit /b 1

'||' tests for an errorlevel higher than 0. This way all batches are called in order but will stop at any error, leaving the screen as it is for you to see any error message.

Cornflakes answered 18/8, 2009 at 12:40 Comment(0)
I
24
call msbuild.bat
call unit-tests.bat
call deploy.bat
Ilyssa answered 9/7, 2009 at 13:49 Comment(0)
S
21

To call a .bat file within a .bat file, use

call foo.bat

(Yes, this is silly, it would make more sense if you could call it with foo.bat, like you could from the command prompt, but the correct way is to use call.)

Stairway answered 9/7, 2009 at 13:50 Comment(0)
P
11

Simplest Way To Run Multiple Batch Files Parallelly

start "systemLogCollector" /min cmd /k call systemLogCollector.bat
start "uiLogCollector" /min cmd /k call uiLogCollector.bat
start "appLogCollector" /min cmd /k call appLogCollector.bat

running-multiple-batch-files Here three batch files are run on separate command windows in a minimized state. If you don't want them minimized, then remove /min. Also, if you don't need to control them later, then you can get rid of the titles. So, a bare-bone command will be- start cmd /k call systemLogCollector.bat


If you want to terminate them, then run these commands-

taskkill /FI "WindowTitle eq appLogCollector*" /T /F
taskkill /FI "WindowTitle eq uiLogCollector*" /T /F
taskkill /FI "WindowTitle eq systemLogCollector*" /T /F
Pompous answered 29/3, 2020 at 16:6 Comment(0)
C
7
Start msbuild.bat
Start unit-tests.bat
Start deploy.bat

If that doesn't work, replace start with call or try this:

Start msbuild.bat
Goto :1
:1
Start unit-tests.bat
Goto :2
:2
Start deploy.bat
Chaco answered 15/8, 2014 at 14:36 Comment(0)
V
6

Looking at your filenames, have you considered using a build tool like NAnt or Ant (the Java version). You'll get a lot more control than with bat files.

Vidette answered 9/7, 2009 at 13:54 Comment(0)
H
6

If you want to open many batch files at once you can use the call command. However, the call command closes the current bat file and goes to another. If you want to open many at once, you may want to try this:

@echo off
start cmd "call ex1.bat&ex2.bat&ex3.bat"

And so on or repeat start cmd "call..." for however many files. This works for Windows 7, but I am not sure about other systems.

Homologous answered 8/5, 2013 at 17:8 Comment(0)
N
6

Your script should be:

start "msbuild.bat"
start "unit-tests.bat"
start "deploy.bat"
Noggin answered 14/3, 2021 at 6:8 Comment(0)
K
3

Just use the call command! Here is an example:

call msbuild.bat
call unit-tests.bat
call deploy.bat
Khelat answered 13/12, 2016 at 4:45 Comment(0)
C
3

With correct quoting (this can be tricky sometimes):

start "" /D "C:\Program Files\ProgramToLaunch" "cmd.exe" "/c call ""C:\Program Files\ProgramToLaunch\programname.bat"""

1st arg - Title (empty in this case)
2nd arg - /D specifies starting directory, can be ommited if want the current working dir (such as "%~dp0")
3rd arg - command to launch, "cmd.exe"
4th arg - arguments to command, with doubled up quotes for the arguments inside it (this is how you escape quotes within quotes in batch)

Ceroplastics answered 17/5, 2019 at 8:41 Comment(0)
A
2

Running multiple scripts in one I had the same issue. I kept having it die on the first one not realizing that it was exiting on the first script.

:: OneScriptToRunThemAll.bat
CALL ScriptA.bat
CALL ScriptB.bat
EXIT

:: ScriptA.bat
Do Foo
EXIT
::ScriptB.bat
Do bar
EXIT

I removed all 11 of my scripts EXIT lines and tried again and all 11 ran in order one at a time in the same command window.

:: OneScriptToRunThemAll.bat
CALL ScriptA.bat
CALL ScriptB.bat
EXIT

::ScriptA.bat
Do Foo

::ScriptB.bat
Do bar
Arlettaarlette answered 21/9, 2012 at 21:4 Comment(2)
don't remove the exits, replace them with goto :eof instead. This will "return" to the callNatalianatalie
you do realize that in a simple batch commands will run in the order they are called also the basic layout for indexes @echo off :menu some commands goto menu note this will run a continuous loop until closed. basically you dont need the :: just :Homologous
M
2

I know I am a bit late to the party, but here is another way. That is, this method should wait until the first one is done, the second, and so on.

start "" /wait cmd.exe /c msbuild.bat
start "" /wait cmd.exe /c unit-tests.bat
start "" /wait cmd.exe /c deploy.bat

The only issue that may come out of using this method, is that with new instances of cmd.exe being spawned, is that Errorlevel checking is kept within in each instance of cmd.exe.

Or..

start "" /wait call msbuild.bat
start "" /wait call unit-tests.bat
start "" /wait call deploy.bat

Hope this helps.

Machinery answered 8/7, 2020 at 14:18 Comment(1)
It is worth emphasizing that without /WAIT it spawns threads simultaneously.Klarrisa

© 2022 - 2024 — McMap. All rights reserved.