我的批处理文件有问题。 它通过这样的方式自动构建几个程序:
所以它看起来像这样:
set FLAG=1
...
gmake all
call :interactive_check
set OTHERFLAG=1
...
gmake all
call :interactive_check
其中有6或7个(它可能会增长)。所以我创建了一个函数来检查errorlevel而不是在每一步复制/粘贴它。 问题是:错误检查是通过函数进行的:
: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
只退出该功能,但不退出批处理文件。
您是否知道如何退出整个批处理文件而无需在每一步复制/粘贴“if errorlevel 1 ..”?
答案 0 :(得分:22)
有关一个好的解决方案,请参阅部件改进版
您可以随时停止批处理,也可以在嵌套函数调用中停止批处理。
您只需要创建一个语法错误,例如使用空块()
来抑制错误消息,可以在调用中执行,并将调用的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
答案 1 :(得分:19)
使用致命语法错误,正如jeb演示的那样,确实会杀死所有批处理,但它也有一个令人讨厌的副作用 - 保留SETLOCAL后环境会发生变化,即使它们应该在批处理结束时通过隐式ENDLOCAL被丢弃。有关详细信息,请参阅我的DosTips帖子SETLOCAL continues after batch termination!。
基于Why does a non-interactive batch script think I've pressed 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级别终止所有批处理的异常,而且还可以在更高级别捕获异常,执行特殊异常处理清理代码,恢复处理,或继续通过另一个抛出退出!有关详细信息,请参阅Does Windows batch support exception handling?。
答案 2 :(得分:2)
当您使用exit /b X
退出该功能时,它会将ERRORLEVEL
设置为X
的值。然后,如果||
之后ERRORLEVEL
为非零,您可以使用call
conditional processing symbol执行其他命令。
@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.
答案 3 :(得分:1)
我建议遵循以下解决方案:
@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's post),因为它也会终止当前批处理文件的调用者。
答案 4 :(得分:0)
@echo off
echo I am %0, calling :subroutine
call:subroutine
NEVER PARSED
exit /b
:subroutine
echo I am %0, calling :recurse
echo Exiting batch script IMMEDIATELY
cmd /c exit /b %=EXIT CODE HERE=%
2>nul call:recurse
NEVER PARSED
exit /b
:recurse - Aborts all batch processing, regardless of CALL depth
call:recurse
NEVER PARSED
exit /b