如何在一个 .BAT 文件中运行多个 .BAT 文件

860

我正在尝试通过我的commit-build.bat文件来执行其他的 .BAT 文件,以便将其作为我们构建过程的一部分。

commit-build.bat 文件内容如下:

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

这似乎很简单,但是commit-build.bat仅执行列表中的第一项(msbuild.bat)。

我已经各自运行了这些文件,没有出现任何问题。


4
@sean - 你不必安装完整的Cygwin包才能让命令行工具正常工作。只需将所有的cygwin dll文件从包中取出,放置在一个指定路径下的目录中,再将所有工具放在另一个指定路径下的目录中就可以了。这样做之后,你就可以使用这些工具了。 - Techie Joe
假设这些文件都是批处理文件,为什么不将它们放在一个大文件中,并使用超时函数来允许每个时间开始? - CMS_95
18个回答

1445

使用:

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

如果不使用 CALL ,当前批处理文件将停止,被调用的批处理文件开始执行。这是一种奇特的行为,可以追溯到早期的 MS-DOS 时代。


9
根据原始DOS规范,若使用无调用(Without call)应执行命令链接,但不返回结果。在“CALL”选项被添加之前,一个流行的选择是打开一个类似于“command /c second.bat”的子命令提示符,因为它也会返回结果。 - Brian Knoblauch
1
我在Windows 7企业版上遇到了这个问题,因此不仅限于XP。 - Rafiki
8
只有第一行在Windows 10上被执行。然而,farheen的答案有效。 - robro
3
如何向批处理文件传递参数,其中一个参数是带有空格的路径。 - Zeus
我使用的是Windows 10,这对我来说非常完美。 - Константин Ван
显示剩余4条评论

204

其他所有答案都是正确的:使用call。例如:

 call "msbuild.bat"

历史

在古老的DOS版本中,无法递归地执行批处理文件。然后引入了调用命令,该命令调用另一个cmd shell来执行批处理文件,并在完成后将执行返回到调用的cmd shell。

显然,在以后的版本中不再需要其他cmd shell。

在早期,许多批处理文件依赖于调用批处理文件不会返回到调用的批处理文件的事实。改变这种行为而不使用额外的语法会破坏许多系统,例如使用批处理文件作为菜单结构的批处理菜单系统。

与许多Microsoft案例一样,向后兼容性是这种行为的原因。

提示

如果您的批处理文件名称中有空格,请在名称周围使用引号:

call "unit tests.bat"

顺便提一下:如果您没有所有批处理文件的名称,也可以使用for来执行此操作(它不能保证正确的批处理文件调用顺序;它遵循文件系统的顺序):

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

您还可以根据调用后的错误级别做出反应。使用:

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

返回一个错误级别。0表示正确执行。在调用批处理文件时,您可以使用该级别进行反应。

if errorlevel neq 0 <batch command>

如果你使用的是比NT4/2000/XP更老的Windows版本,可以使用if errorlevel 1来捕获所有大于等于1的错误级别。

为了控制批处理文件的流程,可以使用goto :-)

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

正如其他人指出的那样:查看构建系统以替换批处理文件。


同意,但在这种情况下,循环可能以错误(字母顺序?)的顺序处理文件。 - Dave Archer
非常好的完整答案。如果您包括控制流程,可能需要注意,可以通过使用call:label1来执行子程序,才能避免使用goto,并且批处理文件中的'return'语句是略微奇怪的goto:eof(无需自己创建eof标签,因为默认情况下已存在)。 - Legolas
errorlevel 命令的示例在 Windows 10 上(在 cmd 控制台中)给了我一个问题。我简单地修改了命令,将其改为 if errorlevel neq echo Houston We have a Problem!。我的批处理过程没有问题,大部分正常完成,但是每一步使用此命令之后,都会出现“neq was unexpected at this time”的错误提示。考虑到可能已经更改了不等于的语法,我尝试使用 !=<>,但是新语法仍然出现了相同的“not expected at this time”错误。我可能做错了什么? - TMWP
请使用 neq 0 替代 TWMP。 - 9pfs

155

如果我们想要打开多个命令提示符,那么可以使用

start cmd /k

/k:是必须的,将会被执行。

可以通过以下方式启动多个命令提示符。

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.

11
这正是我们正在寻找的,因为我们的第一个应用程序阻止了控制台,感谢提示。 - Michael Moeller
1
这将运行多个命令实例,即使运行具有<pause>的多个批处理文件也可以使用。+1,因为这正是我正在寻找的解决方案! - Christian Noel
6
请问您能否解释一下您回答中的那些数字是什么意思?它们的目的不太清楚。 - Kalamalka Kid
5
иҜ·жіЁж„ҸпјҢеӨ§еӨҡж•°дәәеҸҜиғҪеёҢжңӣдҪҝз”Ёstart "зӘ—еҸЈж Үйўҳ" /wait cmd /k call something.batд»ҘдҫҝжҢүйЎәеәҸиҝҗиЎҢдәӢзү©гҖӮ - Andrew
4
(或者使用“start "窗口标题" /wait cmd /c something.bat”命令,其中“cmd /c”表示在完成后关闭窗口。) - Andrew
显示剩余7条评论

44

尝试:

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

32
如果我们有两个批处理脚本aaa.bat和bbb.bat,并像下面这样调用
call aaa.bat
call bbb.bat

当执行该脚本时,它将首先调用aaa.bat,等待aaa.bat线程终止,然后调用bbb.bat。
但是,如果您不想等待aaa.bat终止再调用bbb.bat,请尝试使用START命令:
START ["title"] [/D path] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED]
  [/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL]
  [/AFFINITY <hex affinity>] [/WAIT] [/B] [command/program]
  [parameters]

考试:

start /b aaa.bat
start /b bbb.bat

30

您正在调用多个批处理文件来编译程序。 我默认如果发生错误:
1) 批处理中的程序将以错误级别退出;
2) 您想要知道该错误。

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

'||' 用于检测错误级别是否大于0。这样所有的批处理都会按顺序被调用,但在任何错误处停止,并保留屏幕以便您查看任何错误消息。


30

使用 "&"

正如您所注意到的,直接执行批处理文件而没有使用CALLSTARTCMD /C会导致进入并执行第一个文件,然后随着第一个文件的完成而停止进程。尽管如此,您仍然可以使用&,这与在控制台中直接使用command1 & command2相同:

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

在机器资源方面,这将是最高效的方法,尽管在最后一个块中您将无法使用命令行 GOTOSHIFTSETLOCAL 等功能,并且其功能几乎与在命令提示符中执行命令相同。在最后一个闭合括号之后,您将无法执行其他命令。

使用 CALL

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

在大多数情况下,这将是最佳方法——它不会创建一个单独的进程,但其行为几乎与调用子程序作为:label相同。 在MS术语中,它创建一个新的“批处理文件上下文并将控制传递到指定标签后的语句。第一次遇到批处理文件结尾(即跳转到标签后),控制返回到调用语句之后的语句。

您可以使用在被调用文件中设置的变量(如果它们没有在SETLOCAL块中设置),您可以直接访问被调用文件中的标签

CMD /C,管道,FOR /F

其他一种本地选项是使用CMD /C (/C开关将强制调用控制台退出并返回控制权)。 这是cmd.exe通过使用FOR /F针对bat文件或使用管道时以非透明方式执行的内容。 这将生成一个具有调用bat的所有环境的子进程。 从资源效率来看不如其他方法,但由于该进程是单独的,所以解析崩溃或调用EXIT命令不会停止调用的.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

允许更灵活地启动脚本,可以在单独的窗口中启动它们,不必等待它们完成,设置一个标题等等。默认情况下,使用CMD /K启动.bat.cmd脚本,这意味着生成的脚本不会自动关闭。再次将所有环境传递给已启动的脚本,并且比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

与现在的其他方法不同,下面的示例将使用CMD.exe之外的实用程序(默认仍在Windows上可用)。 WMIC实用程序将创建完全独立的进程,因此您将无法直接等待其完成。但是,WMIC最好的功能是它返回生成进程的ID:

:: 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%

你还可以使用它来在远程计算机上以不同用户等方式启动进程。

SCHTASKS

SCHTASKS提供了一些特性,如(显而易见的)调度,作为另一个用户(甚至是系统用户)运行,远程启动等。再次启动时处于完全独立的环境(即它自己的变量),甚至可以隐藏进程,具有命令参数的xml文件等:

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

在这里,PID也可以从事件日志中获取。

ScriptRunner

提供启动脚本之间的一些超时时间。基本交易功能(即发生错误时回滚),并且参数可以放在单独的XML文件中。

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

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

21

要在一个 .bat 文件中调用另一个 .bat 文件,使用以下命令:

call foo.bat

(是的,这很傻,如果您可以像在命令提示符中一样使用foo.bat调用它,那将更有意义,但正确的方法是使用call。)


11

同时运行多个批处理文件的最简单方法

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 这里有三个批处理文件在单独的命令窗口中以最小化状态运行。如果你不想让它们最小化,那么删除 /min。另外,如果你之后不需要控制它们,那么可以去掉标题。所以,一个简单的命令将是- start cmd /k call systemLogCollector.bat


如果您想终止它们,则运行以下命令-
taskkill /FI "WindowTitle eq appLogCollector*" /T /F
taskkill /FI "WindowTitle eq uiLogCollector*" /T /F
taskkill /FI "WindowTitle eq systemLogCollector*" /T /F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接