我的batch file有问题。 它通过做这样的事情自动build立几个程序:
所以看起来像这样:
set FLAG=1 ... gmake all call :interactive_check set OTHERFLAG=1 ... gmake all call :interactive_check
有6或7这些(它可能会增长)。 所以我做了一个函数来检查错误级别,而不是每一步复制/粘贴它。 问题是这样的:通过一个函数进行错误检查:
:interactive_check if errorlevel 1 ( echo. echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ echo Error in compilation process... exiting echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ echo. cd %root_dir% exit /B 1 ) ELSE ( echo.Continuing to next step ) goto:eof
现在,运行它时, exit /B 1
只是退出函数, 而不是batch file 。
你知道如何退出完整的batch file,而不必复制/粘贴我的“如果errorlevel 1 ..”在每一步?
如jeb所示,使用一个致命的语法错误可以终止所有批处理,但是它也有一个令人讨厌的副作用 – 在SETLOCAL被保留之后环境发生变化,尽管在批处理结束时它们应该被隐式ENDLOCAL抛弃。 看到我的DosTips文章SETLOCAL批处理终止后继续! 了解更多信息。
根据为什么一个非交互式批处理脚本认为我已经按下control-C? ,我已经发现了一个干净的方式来退出CALLed例程或脚本中的所有批处理脚本,并且在SETLOCAL之后的所有更改都被正确丢弃。
@echo off setlocal 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
这里是运行上面的test.bat的示例输出。 您可以看到脚本永远不会从:ExitBatch调用返回,并且一旦批处理终止,测试变量定义就会被正确丢弃。
C:\test>test.bat test=AFTER sub SETLOCAL 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
重要更新:
现在可以使用纯批量实现强大的异常处理。 你不仅可以抛出一个异常,可以终止来自任何CALL级别的所有批处理,而且还可以在更高级别捕获异常,优先执行特殊的异常处理清除代码,并恢复处理,或者通过另一个抛出继续退出! 请参阅Windows批处理是否支持异常处理? 获取更多信息。
对于一个好的解决方案,请参阅部分改进版本
您可以在任何时候停止批处理,也可以在嵌套的函数调用中停止批处理。
你只需要创建一个语法错误,例如用一个空的block ()
来抑制错误信息,它可以在一个调用中执行,并且调用的stderr被重定向到nul。
@echo off setlocal enabledelayedexpansion rem Do something call :interactive_check rem Do something call :interactive_check goto :eof :::::::::::::::::::::::::: :interactive_check if errorlevel 1 ( echo. echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ echo Error in compilation process... exiting echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ call :halt 1 ) ELSE ( echo.Continuing to next step ) goto :eof :: Sets the errorlevel and stops the batch immediately :halt call :__SetErrorLevel %1 call :__ErrorExit 2> nul goto :eof :__ErrorExit rem Creates a syntax error, stops immediately () goto :eof :__SetErrorLevel exit /b %time:~-2% goto :eof
2017-04-09改进版本:只退出当前批次,但不是调用者批次
正如@dbenham所说,异常处理有一个新的技术,也可以用于只退出当前批处理。
@echo off echo Do something, detecting some fatal error call :ExitBatch 3 exit /b :ExitBatch [errorcode] - Exits only the current batch file, regardless how many CALLs set _errLevel=%1 REM *** Remove all calls from the current batch from the call stack :popStack ( (goto) 2>nul setlocal DisableDelayedExpansion call set "caller=%%~0" call set _caller=%%caller:~0,1%% call set _caller=%%_caller::=%% if not defined _caller ( REM callType = func rem set _errLevel=%_errLevel% goto :popStack ) (goto) 2>nul endlocal cmd /c "exit /b %_errLevel%" ) echo NEVER REACHED exit /b
当使用exit /b X
退出函数时,它将ERRORLEVEL
设置为X
的值。 然后你可以使用||
如果ERRORLEVEL
在call
后不为零,则执行另一个命令。
@echo off setlocal call :myfunction PASS || goto :eof call :myfunction FAIL || goto :eof echo Execution never gets here goto :eof :myfunction if "%1"=="FAIL" ( echo myfunction: got a FAIL. Will exit. exit /b 1 ) echo myfunction: Everything is good. exit /b 0
这个脚本的输出是:
myfunction: Everything is good. myfunction: got a FAIL. Will exit.
我建议以下解决方案:
@echo off :: comment next line if you want to export any local variables in caller environment setlocal set FLAG=1 rem Do something call :interactive_check set FLAG2=2 rem Do something call :interactive_check goto :eof :interactive_check if errorlevel 1 ( echo. echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ echo Error in compilation process... exiting echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ (goto) 2>nul & endlocal & exit /b %ERRORLEVEL% ) else ( echo Continuing to next step ) goto :eof
它保存错误代码从命令产生错误。 如果要将错误代码保存到特定值,请修改该行:
(goto) 2>nul & endlocal & exit /b YOUR_EXITCODE_HERE
我不喜欢语法错误的解决方案(见jeb的帖子 ),因为它也终止了当前批处理文件的调用者。