Exit batch script from inside a function Exit batch script from inside a function windows windows

Exit batch script from inside a function


For a good solution see the part improved version

You can stop a batch at any point, also inside of nested function calls.

You only need to create a syntax error, for example with an empty block (), to suppress the error message, it can be executed in a call, and the stderr of the call is redirected to nul.

@echo offsetlocal enabledelayedexpansionrem Do somethingcall :interactive_checkrem Do somethingcall :interactive_checkgoto :eof:::::::::::::::::::::::::::interactive_checkif 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:haltcall :__SetErrorLevel %1call :__ErrorExit 2> nulgoto :eof:__ErrorExitrem Creates a syntax error, stops immediately() goto :eof:__SetErrorLevelexit /b %time:~-2%goto :eof

2017-04-09 Improved version: Exit only the current batch, but not the caller batch

As @dbenham mentioned, there is a new technic for exception handling that can also be used for exiting only the current batch.

@echo offecho Do something, detecting some fatal errorcall :ExitBatch 3exit /b:ExitBatch [errorcode] - Exits only the current batch file, regardless how many CALLsset _errLevel=%1REM *** 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 REACHEDexit /b


Using a fatal syntax error, as jeb demonstrates, does kill all batch processing, but it also has a nasty side effect - environment changes after SETLOCAL are preserved, even though they are supposed to be discarded via implicit ENDLOCAL when batch processing ends. See my DosTips post SETLOCAL continues after batch termination! for more information.

Based on information at Why does a non-interactive batch script think I've pressed control-C?, I have discovered a clean way to exit all batch scripting from within a CALLed routine or script, and all changes after SETLOCAL are properly discarded.

@echo offsetlocalset test=AFTER main SETLOCALcall :subecho returning from main  NEVER REACHEDexit /b:subsetlocalset test=AFTER sub SETLOCALset testcall :ExitBatchecho returning from sub2 NEVER REACHEDexit /b:ExitBatch - Cleanly exit batch processing, regardless how many CALLsif not exist "%temp%\ExitBatchYes.txt" call :buildYescall :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1:CtrlCcmd /c exit -1073741510:buildYes - Establish a Yes file for the language used by the OSpushd "%temp%"set "yes="copy nul ExitBatchYes.txt >nulfor /f "delims=(/ tokens=2" %%Y in (  '"copy /-y nul ExitBatchYes.txt <nul"') do if not defined yes set "yes=%%Y"echo %yes%>ExitBatchYes.txtpopdexit /b

Here is sample output of running the above test.bat. You can see that the script never returned from the :ExitBatch call, and the test variable definition has been properly discarded once batch processing terminates.

C:\test>test.battest=AFTER sub SETLOCALC:\test>set testEnvironment variable test not definedC:\test>

The :ExitBatch routine can be put into its own ExitBatch.bat script and placed somewhere within your PATH such that it can be conveniently used by any batch script.

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

Important Update:

It is now possible to implement robust exception handling with pure batch. Not only can you throw an exception that can terminate all batch processing from any CALL level, but you can also catch the exception at a higher level, excecute special exception handling cleanup code, and resume processing, or continue to exit via another throw! See Does Windows batch support exception handling? for more info.


When you use exit /b X to exit from the function it sets ERRORLEVEL to the value of X. You can then use the || conditional processing symbol to execute another command if ERRORLEVEL is non-zero after the call.

@echo offsetlocalcall :myfunction PASS || goto :eofcall :myfunction FAIL || goto :eofecho Execution never gets heregoto :eof:myfunction    if "%1"=="FAIL" (         echo myfunction: got a FAIL. Will exit.        exit /b 1    )    echo myfunction: Everything is good.    exit /b 0

Output from this script is:

myfunction: Everything is good.myfunction: got a FAIL. Will exit.