【问题标题】:Exit from nested batch file退出嵌套批处理文件
【发布时间】:2013-07-13 09:11:07
【问题描述】:

我有 4 个批处理文件,假设是 a.bat、b.bat、c.bat 和 d.bat。现在这些批处理文件的调用方式是 a.bat 调用 b.bat,b.bat 调用 c.call 等等。

如果我在任何批处理文件中遇到任何错误,我想通过说发生错误来退出整个程序,并说明哪个批处理文件有问题。 我的问题是,我该怎么做?

这里我使用了exit /b,但它只从当前的批处理文件中取出并移回到调用它的批处理文件中:

a.bat

@echo. off
echo. this is batch 'a'
call b.bat

b.bat

@echo. off
echo. this is batch 'b'
call c.bat

c.bat

@echo. off
echo. this is batch 'c'

我在批处理“C”中遇到错误 - 然后它应该报告错误并退出,但它以某种方式移回批处理“B”。关于如何退出嵌套批处理文件的任何想法?

【问题讨论】:

    标签: windows batch-file cmd call exit


    【解决方案1】:

    如果 .BAT 文件在 TakeCommand 下,请使用 CANCEL。

    【讨论】:

      【解决方案2】:

      jeb 的致命语法错误方法有效,但它不能正确终止任何活动的 SETLOCAL。

      例如,这里是 fatalTest.bat:

      @echo off
      setlocal enableDelayedExpansion
      set test=AFTER main SETLOCAL
      call :sub
      echo returning from main  NEVER REACHED
      exit /b
      
      :sub
      setlocal
      set test=AFTER sub SETLOCAL
      set test
      call :ExitBatch
      echo returning from sub2 NEVER REACHED
      exit /b
      
      
      :ExitBatch
      call :__exitBatch 2>nul
      :__ExitBatch
      for
      

      这里是示例运行输出,展示了如何在批处理终止后仍然定义测试和延迟扩展:

      C:\test>fatalTest
      test=AFTER sub SETLOCAL
      
      C:\test>echo !test!
      AFTER sub SETLOCAL
      
      C:\test>
      

      现在无法将环境恢复到批处理前状态。应该终止 CMD.EXE 会话。


      这是一个改进的 CtrlCTest.bat 版本,可以在批处理终止时正确终止任何活动的 SETLOCAL。它使用了一种令人惊讶的技术来以编程方式“按下”Ctrl-C,我在 Why does a non-interactive batch script think I've pressed control-C? 了解到这一点

      @echo off
      setlocal enableDelayedExpansion
      set test=AFTER main SETLOCAL
      call :sub
      echo returning from main  NEVER REACHED
      exit /b
      
      :sub
      setlocal
      set test=AFTER sub SETLOCAL
      set test
      call :ExitBatch
      echo returning from sub2 NEVER REACHED
      exit /b
      
      
      :ExitBatch - Cleanly exit batch processing, regardless how many CALLs
      if not exist "%temp%\ExitBatchYes.txt" call :buildYes
      call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1
      :CtrlC
      cmd /c exit -1073741510
      
      :buildYes - Establish a Yes file for the language used by the OS
      pushd "%temp%"
      set "yes="
      copy nul ExitBatchYes.txt >nul
      for /f "delims=(/ tokens=2" %%Y in (
        '"copy /-y nul ExitBatchYes.txt <nul"'
      ) do if not defined yes set "yes=%%Y"
      echo %yes%>ExitBatchYes.txt
      popd
      exit /b
      

      这是示例运行输出。可以看到延迟扩展不再活跃,测试也不再定义:

      C:\test>CtrlCTest
      test=AFTER sub SETLOCAL
      
      C:\test>echo !test!
      !test!
      
      C:\test>set test
      Environment variable test not defined
      
      C:\test>
      

      您可以将 :ExitBatch 例程放在独立的 ExitBatch.bat 脚本中,该脚本位于 PATH 中的某个位置,然后任何批处理都可以根据需要方便地调用该实用程序。

      @echo off
      :ExitBatch - Cleanly exit batch processing, regardless how many CALLs
      if not exist "%temp%\ExitBatchYes.txt" call :buildYes
      call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1
      :CtrlC
      cmd /c exit -1073741510
      
      :buildYes - Establish a Yes file for the language used by the OS
      pushd "%temp%"
      set "yes="
      copy nul ExitBatchYes.txt >nul
      for /f "delims=(/ tokens=2" %%Y in (
        '"copy /-y nul ExitBatchYes.txt <nul"'
      ) do if not defined yes set "yes=%%Y"
      echo %yes%>ExitBatchYes.txt
      popd
      exit /b
      

      【讨论】:

        【解决方案3】:

        您可以将错误级别与退出代码一起使用,如下所述:http://www.robvanderwoude.com/errorlevel.php

        特别是,如果您想手动出错,那么 c.bat 或 b.bat 应该明确指定退出代码

        EXIT /b 1
        

        (或您选择的数字),但如果您只想计算 windows 自动错误,那么在运行 b.bat 或 c.bat 之后,您可以编写

        IF ERRORLEVEL 1 EXIT /b %ERRORLEVEL%
        

        这会将相同的错误传播到下一个程序,因此如果您愿意,它们可以立即退出。优点是您可以随时停止向上传播。

        (编辑:要清楚,这里提到的第二行代码在除底层程序之外的所有程序中都是必需的,无论您使用的是手动错误还是自动错误)

        【讨论】:

        • 这不会破坏链条。
        • 恐怕我不理解你和 jeb 认为他所要求的用例,因此,我给他/我认为他所要求的答案,哪个是“我希望 b.bat 在出现 c.bat 错误后停止运行我在其中指定的其余代码,并且我希望 a.bat 对 b.bat 执行相同的操作”。如果我对他的意思有误,他显然会接受你的一个答案而不是我的答案。
        • 来自问题:Here I used exit /b but it only gets out from the current batch file and moves back into batch file from whence it was called。我对合理使用一无所知。这可能是,但超出了我的范围。审核不是我的部门。
        【解决方案4】:

        您可以使用语法错误,这会立即停止批处理而不关闭命令窗口。

        :HALT 函数调用:__halt 函数只是为了抑制错误消息。

        c.bat

        @echo off
        echo this is batch 'c'
        echo An error occurs
        call :HALT
        exit /b
        
        :HALT
        call :__halt 2> nul
        exit /b
        
        :__halt
        ()
        

        【讨论】:

        • 你可以在没有额外的:HALT 的情况下做到这一点,在 XP 中工作,没有错误消息。我的意思是直接打电话给:__halt 2&gt;nul
        • @Endoro 很明显,但我想提供一个 HALT 函数来调用而无需任何额外文本
        • +1 以获得巧妙的解决方案。但是,我相信,如果您知道自己处于故障点,那么脚本应该在运行时优雅地退出并提供有意义的输出。
        • 这个聪明的技术有一个不幸的副作用——在致命的语法错误之后,SETLOCAL 没有正确终止。请参阅my answer 了解另一种更干净地终止批处理的方法。
        【解决方案5】:

        你可以试试这个(c.bat):

        @echo. this is batch 'c'
        @pause
        exit
        

        【讨论】:

        • 是的,但是 OP 可以调用批处理 cmd /c a.bat。这不会关闭窗口。但你的很好。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-07
        • 1970-01-01
        相关资源
        最近更新 更多