作为我们构建过程的一部分,我正试图让我的 commit-build.bat
执行其他 .BAT 文件。
commit-build.bat
的内容:
"msbuild.bat"
"unit-tests.bat"
"deploy.bat"
这看起来很简单,但 commit-build.bat
只执行列表中的第一项 (msbuild.bat
)。
我已经单独运行了每个文件,没有任何问题。
利用:
call msbuild.bat
call unit-tests.bat
call deploy.bat
不使用 CALL 时,当前批处理文件停止,被调用的批处理文件开始执行。这是一种可以追溯到早期 MS-DOS 时代的特殊行为。
所有其他答案都是正确的:使用呼叫。例如:
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>
如果您的 Windows 比 NT4/2000/XP 更旧,请使用 if errorlevel 1
来捕获所有错误级别 1 和更高级别。
要控制批处理文件的流程,有 goto :-(
if errorlevel 2 goto label2
if errorlevel 1 goto label1
...
:label1
...
:label2
...
正如其他人指出的那样:查看构建系统以替换批处理文件。
errorlevel
命令示例在 Windows 10(在 cmd 控制台中)上给了我一个问题。我将命令简单地修改为 if errorlevel neq echo Houston We have a Problem!
。我的批处理没有问题,并且大部分都正常完成,但是在调用语句之后使用此命令的每一步,我都得到“此时 neq 是意外的”。考虑到他们可能更改了不相等的语法,我尝试了 !=
和 <>
,但新语法仍然出现相同的“此时未预期”错误。我做错了什么?
neq 0
。
如果我们想打开多个命令提示符,那么我们可以使用
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.
start "Window title" /wait cmd /k call something.bat
来按顺序运行。
start "Window title" /wait cmd /c something.bat
,其中 cmd /c
完成后关闭窗口)
尝试:
call msbuild.bat
call unit-tests.bat
call deploy.bat
您正在调用多个批次以编译程序。如果发生错误,我想当然地认为: 1)批处理中的程序将以错误级别退出; 2)你想知道它。
for %%b in ("msbuild.bat" "unit-tests.bat" "deploy.bat") do call %%b|| exit /b 1
'||'测试高于 0 的错误级别。这样所有批次都按顺序调用,但会在任何错误时停止,让屏幕保持原样,让您看到任何错误消息。
如果我们有两个批处理脚本,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
call msbuild.bat
call unit-tests.bat
call deploy.bat
要在 .bat
文件中调用 .bat
文件,请使用
call foo.bat
(是的,这很愚蠢,如果您可以使用 foo.bat
调用它会更有意义,就像您可以在命令提示符下一样,但正确的方法是使用 call
。)
使用 ”&”
正如您已经注意到在没有 CALL
、START
、CMD /C
的情况下直接执行 bat 会导致进入并执行第一个文件,然后在第一个文件完成时进程停止。虽然您仍然可以使用 &
,这与直接在控制台中使用 command1 & command2
相同:
(
first.bat
)&(
second.bat
)& (
third.bat
)&(
echo other commands
)
就机器资源而言,这将是最有效的方式,尽管在最后一个块中您将无法使用命令行 GOTO
、SHIFT
、SETLOCAL
.. 并且其功能几乎与在命令提示符下执行命令。并且您将无法在最后一个右括号之后执行其他命令
使用呼叫
call first.bat
call second.bat
call third.bat
在大多数情况下,这将是最好的方法 - 它不会创建单独的进程,但具有与调用 :label
作为子例程几乎相同的行为。在MS术语中,它创建一个新的“批处理文件上下文并将控制权传递给指定标签之后的语句。第一次遇到批处理文件的结尾(即跳转到标签后),控制权返回到后面的语句通话声明。”
您可以使用在被调用文件中设置的变量(如果它们未在 SETLOCAL
块中设置),您可以使用 access directly labels in the called file。
CMD /C,管道,FOR /F
其他 native
选项是使用 CMD /C
(/C 开关将强制被调用的控制台退出并返回控制) cmd.exe 以非透明方式对 bat 文件使用 FOR /F
或管道时执行的操作被使用。这将产生一个子进程,该进程将拥有调用 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
开始
允许您更灵活地在单独的窗口中启动脚本,不等待它们完成,设置标题等。默认情况下,它以 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
并行运行多个批处理文件的最简单方法
start "systemLogCollector" /min cmd /k call systemLogCollector.bat
start "uiLogCollector" /min cmd /k call uiLogCollector.bat
start "appLogCollector" /min cmd /k call appLogCollector.bat
https://i.stack.imgur.com/Gq0PL.png
如果要终止它们,请运行以下命令-
taskkill /FI "WindowTitle eq appLogCollector*" /T /F
taskkill /FI "WindowTitle eq uiLogCollector*" /T /F
taskkill /FI "WindowTitle eq systemLogCollector*" /T /F
Start msbuild.bat
Start unit-tests.bat
Start deploy.bat
如果这不起作用,请将 start
替换为 call
或尝试以下操作:
Start msbuild.bat
Goto :1
:1
Start unit-tests.bat
Goto :2
:2
Start deploy.bat
你的脚本应该是:
start "msbuild.bat"
start "unit-tests.bat"
start "deploy.bat"
如果要一次打开多个批处理文件,可以使用 call 命令。但是,调用命令会关闭当前的 bat 文件并转到另一个文件。如果你想一次打开很多,你可能想试试这个:
@echo off
start cmd "call ex1.bat&ex2.bat&ex3.bat"
依此类推,或者对许多文件重复 start cmd
"call
..."。这适用于 Windows 7,但我不确定其他系统。
正确引用(有时这可能很棘手):
start "" /D "C:\Program Files\ProgramToLaunch" "cmd.exe" "/c call ""C:\Program Files\ProgramToLaunch\programname.bat"""
第 1 个参数 - 标题(在这种情况下为空) 第 2 个参数 - /D 指定起始目录,如果想要当前工作目录可以省略(例如“%~dp0”) 第 3 个参数 - 要启动的命令,“cmd.exe” 第 4 个arg - 命令的参数,其中的参数加倍引号(这是您批量转义引号中的引号的方式)
在一个脚本中运行多个脚本我遇到了同样的问题。我一直让它在第一个脚本上死掉,却没有意识到它在第一个脚本上退出。
:: OneScriptToRunThemAll.bat
CALL ScriptA.bat
CALL ScriptB.bat
EXIT
:: ScriptA.bat
Do Foo
EXIT
::ScriptB.bat
Do bar
EXIT
我删除了所有 11 个脚本 EXIT 行并再次尝试,所有 11 个脚本在同一个命令窗口中一次按顺序运行。
:: OneScriptToRunThemAll.bat
CALL ScriptA.bat
CALL ScriptB.bat
EXIT
::ScriptA.bat
Do Foo
::ScriptB.bat
Do bar
exit
,而是用 goto :eof
替换它们。这将“返回”到 call
@echo off :menu some commands goto menu
注意这将运行一个连续循环,直到关闭。基本上你不需要 ::
只是 :
只需使用 call
命令!这是一个例子:
call msbuild.bat
call unit-tests.bat
call deploy.bat
我知道我参加聚会有点晚了,但这是另一种方式。也就是说,这个方法应该等到第一个完成,第二个完成,以此类推。
start "" /wait cmd.exe /c msbuild.bat
start "" /wait cmd.exe /c unit-tests.bat
start "" /wait cmd.exe /c deploy.bat
使用此方法可能产生的唯一问题是,随着新的 cmd.exe 实例的生成,错误级别检查保留在每个 cmd.exe 实例中。
或者..
start "" /wait call msbuild.bat
start "" /wait call unit-tests.bat
start "" /wait call deploy.bat
希望这可以帮助。
不定期副业成功案例分享