【问题标题】:How to run multiple .BAT files within a .BAT file如何在一个 .BAT 文件中运行多个 .BAT 文件
【发布时间】:2010-11-09 09:26:17
【问题描述】:

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

commit-build.bat的内容:

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

这看起来很简单,但commit-build.bat 只执行列表中的第一项 (msbuild.bat)。

我已经单独运行了每个文件,没有任何问题。

【问题讨论】:

  • @sean - 您无需安装完整的 Cygwin 软件包即可使用命令行工具。只需从包中取出所有 cygwin dll,将它们放在路径目录中,将所有工具放在另一个路径目录中,就可以了。
  • 假设这些文件中的每一个都只是批处理为什么不将它们放在一个大文件中并使用超时功能来允许每次启动。

标签: batch-file cmd


【解决方案1】:

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

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

这里三个批处理文件以最小化状态在单独的命令窗口上运行。如果您不希望它们最小化,请删除 /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

【讨论】:

    【解决方案2】:

    你的脚本应该是:

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

    【讨论】:

      【解决方案3】:

      使用“&

      正如您注意到的那样,直接执行 bat 而不使用 CALLSTARTCMD /C 会导致进入并执行第一个文件,然后在第一个文件完成时进程停止。虽然您仍然可以使用&,这与直接在控制台中使用command1 & command2 相同:

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

      就机器资源而言,这将是最有效的方式,但在最后一个区块中,您将无法使用命令行GOTO,SHIFT,SETLOCAL.. 它的功能几乎是与在命令提示符下执行命令相同。并且在最后一个右括号之后您将无法执行其他命令

      Using 致电

      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
      

      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
      

      【讨论】:

        【解决方案4】:

        我知道我参加聚会有点晚了,但这是另一种方式。也就是说,这个方法应该等到第一个完成,第二个完成,以此类推。

        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
        

        希望这会有所帮助。

        【讨论】:

        • 值得强调的是,如果没有 /WAIT,它会同时产生线程。
        【解决方案5】:

        正确引用(有时这可能很棘手):

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

        第一个参数 - 标题(在这种情况下为空)
        第二个参数 - /D 指定起始目录,如果想要当前工作目录可以省略(例如“%~dp0”)
        第三个参数 - 要启动的命令,“cmd.exe”
        第 4 个 arg - 命令的参数,其中的参数加倍引号(这是您批量转义引号中的引号的方式)

        【讨论】:

          【解决方案6】:

          只需使用call 命令!这是一个例子:

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

          【讨论】:

            【解决方案7】:

            如果我们有两个批处理脚本,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
            

            【讨论】:

              【解决方案8】:

              如果你想一次打开多个批处理文件,你可以使用 call 命令。但是,调用命令会关闭当前的 bat 文件并转到另一个文件。如果你想一次打开很多,你可能想试试这个:

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

              等等,或者对许多文件重复 start cmd "call..."。这适用于 Windows 7,但我不确定其他系统。

              【讨论】:

                【解决方案9】:

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

                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.
                

                【讨论】:

                • 这就是我们正在搜索的内容,因为我们的第一个应用程序阻塞了控制台,感谢您的提示
                • 这将运行多个命令实例,甚至可以运行多个具有 的批处理文件。 +1,因为这正是我正在寻找的解决方案!
                • 您能解释一下这些数字在您的答案中吗?他们的目的还不清楚。
                • 请注意,大多数人可能希望使用start "Window title" /wait cmd /k call something.bat 来按顺序运行。
                • (或start "Window title" /wait cmd /c something.bat,其中cmd /c 完成后关闭窗口)
                【解决方案10】:

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

                 call "msbuild.bat"
                

                历史

                在古老的 DOS 版本中,无法递归执行批处理文件。然后引入 call 命令,调用另一个 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
                ...
                

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

                【讨论】:

                • 同意,但在这种情况下,循环可能会以错误的(字母顺序?)顺序处理文件
                • 不错且非常完整的答案。如果您包含控制流,最好注意,您可以使用 call :label1 来执行子例程,而不是 goto,并且批处理文件中的“return”语句是有点奇怪的 goto :eof(并且不需要自己制作一个eof标签,默认存在)。
                • errorlevel 命令示例在 Windows 10 上(在 cmd 控制台中)给了我一个问题。我将命令修改为if errorlevel neq echo Houston We have a Problem!。我的批处理过程没有问题,并且大部分都正常完成,但是在调用语句之后使用此命令的每一步,我都得到“此时 neq 是意外的”。考虑到他们可能已经改变了不相等的语法,我尝试了!=&lt;&gt;,但新语法仍然出现相同的“此时不是预期的”错误。我可能做错了什么?
                • TWMP 请改用neq 0
                【解决方案11】:

                查看您的文件名,您是否考虑过使用像 NAnt 或 Ant(Java 版本)这样的构建工具。您将获得比使用 bat 文件更多的控制权。

                【讨论】:

                  【解决方案12】:

                  试试:

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

                  【讨论】:

                    【解决方案13】:

                    用途:

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

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

                    【讨论】:

                    • 奇怪,我试过在 Windows 7 上不使用“调用”,我记得它有效,但在 windows xp 上它需要这个命令。可以吗?
                    • 没有调用,根据原始 DOS 规范,应该执行命令链接而不是返回。添加“CALL”之前的一个流行选项是打开一个子命令提示符,例如“command /c second.bat”,因为它也会返回。
                    • 我在 Windows 7 企业版上遇到了问题,所以不仅仅是 xp
                    • 在 Windows 10 上只执行第一行。然而,farheen 的回答奏效了。
                    • 如何将参数传递给批处理文件,其中一个参数是带空格的路径。
                    【解决方案14】:

                    您正在调用多个批处理来编译程序。 如果发生错误,我想当然地认为:
                    1) 批处理中的程序将以错误级别退出;
                    2) 你想知道它。

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

                    '||'测试高于 0 的错误级别。这样所有批次都会按顺序调用,但会在出现任何错误时停止,让屏幕保持原样以供您查看任何错误消息。

                    【讨论】:

                      【解决方案15】:
                      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
                      

                      【讨论】:

                        【解决方案16】:

                        同时运行多个脚本我遇到了同样的问题。我一直让它在第一个脚本上死掉,却没有意识到它在第一个脚本上退出。

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

                        【讨论】:

                        • 不要删除exits,而是用goto :eof 替换它们。这将“返回”到call
                        • 您确实意识到,在一个简单的批处理命令中,命令将按照它们被调用的顺序运行,这也是索引的基本布局@echo off :menu some commands goto menu 注意这将运行一个连续循环,直到关闭。基本上你不需要:: 只是:
                        【解决方案17】:

                        要在.bat 文件中调用.bat 文件,请使用

                        call foo.bat
                        

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

                        【讨论】:

                          【解决方案18】:
                          call msbuild.bat
                          call unit-tests.bat
                          call deploy.bat
                          

                          【讨论】:

                            猜你喜欢
                            • 2010-10-13
                            • 1970-01-01
                            • 2021-06-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2022-10-13
                            • 1970-01-01
                            • 1970-01-01
                            • 2020-05-10
                            相关资源
                            最近更新 更多