How can I exit a batch file from inside a subroutine?

If I use the EXIT command, I simply return to the line where I called the subroutine, and execution continues.

Here's an example:

@echo off ECHO Quitting... CALL :QUIT ECHO Still here! GOTO END :QUIT EXIT /B 1 :END EXIT /B 0 

Output:

Quitting... Still here! 

Update:

This isn't a proper answer, but I ended up doing something along the lines of:

@echo off CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL ECHO You shouldn't see this! GOTO END :SUBROUTINE_WITH_ERROR ECHO Simulating failure... EXIT /B 1 :HANDLE_FAIL ECHO FAILURE! EXIT /B 1 :END ECHO NORMAL EXIT! EXIT /B 0 

The double-pipe statement of:

CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL 

is shorthand for:

CALL :SUBROUTINE_WITH_ERROR IF ERRORLEVEL 1 GOTO HANDLE_FAIL 

I would still love to know if there's a way to exit directly from a subroutine rather than having to make the CALLER handle the situation, but this at least gets the job done.


Update #2: When calling a subroutine from within another subroutine, called in the manner above, I call from within subroutines thusly:

CALL :SUBROUTINE_WITH_ERROR || EXIT /B 1 

This way, the error propagates back up to the "main", so to speak. The main part of the batch can then handle the error with the error handler GOTO :FAILURE

5 Answers

Add this to the top of your batch file:

@ECHO OFF SETLOCAL IF "%selfWrapped%"=="" ( REM this is necessary so that we can use "exit" to terminate the batch file, REM and all subroutines, but not the original cmd.exe SET selfWrapped=true %ComSpec% /s /c ""%~0" %*" GOTO :EOF ) 

Then you can simply call:

  • EXIT [errorLevel] if you want to exit the entire file
  • EXIT /B [errorLevel] to exit the current subroutine
  • GOTO :EOF to exit the current subroutine
4

How about this one minor adjustment?

@echo off ECHO Quitting... CALL :QUIT :: The QUIT subroutine might have set the error code so let's take a look. IF ERRORLEVEL 1 GOTO :EOF ECHO Still here! GOTO END :QUIT EXIT /B 1 :END EXIT /B 0 

Output:

Quitting... 

Technically this doesn't exit from within the subroutine. Rather, it simply checks the result of the subroutine and takes action from there.

2

This will exit current context and a parent context (i.e., when executed inside a one call deep subroutine script will exit):

(goto) 2>nul || exit /b 

Or, if you need errorlevel 0:

(goto) 2>nul || ( type nul>nul exit /b ) 

Basically, (goto) 2>nul sets errorlevel to 1 (without outputting an error), returns execution to the parent context and code after double pipe is executed in parent context. type nul>nul sets errorlevel to 0.

UPD:

To return execution more than twice in a row, chain several (goto) 2>nul || like this:

(goto) 2>nul || (goto) 2>nul || (goto) 2>nul || ( type nul>nul exit /b ) 

Here's a recursive subroutine to return context a variable number of times:

:Kill (goto) 2>nul || ( set /a depth=%1-1 if %1 GEQ 1 ( call:Kill !depth! ) (goto) 2>nul || (type nul>nul) ) 

When called from a recursive function:

@echo off setlocal EnableDelayedExpansion call:Recurs 5 echo This won't be printed exit /b :Recurs set /a ri+=1 echo %ri% if %ri% LSS %1 ( call:Recurs %1 ) echo This will be printed only once call:Kill %1 exit /b 

the output will be:

1 2 3 4 5 This will be printed only once 

If you do not want to come back from the procedure, don't use call: instead use goto.

@echo off ECHO Quitting... GOTO :QUIT ECHO Will never be there! GOTO END :QUIT EXIT /B 1 :END EXIT /B 0 
1

I put error handling in my batch files. You can call error handlers like this:

CALL :WARNING "This is" "an important" "warning." 

And here is the end of the batch file:

::------------------------------------------------------------------- :: Decisions ::------------------------------------------------------------------- :INFO IF "_DEBUG"=="true" ( ECHO INFO: %~1 IF NOT "%~2"=="" ECHO %~2 IF NOT "%~3"=="" ECHO %~3 ) EXIT /B 0 :WARNING ECHO WARNING: %~1 IF NOT "%~2"=="" ECHO %~2 IF NOT "%~3"=="" ECHO %~3 EXIT /B 0 :FAILURE ECHO FAILURE: %~1 IF NOT "%~2"=="" ECHO %~2 IF NOT "%~3"=="" ECHO %~3 pause>nul :END ECHO Closing Server.bat script FOR /l %%a in (5,-1,1) do (TITLE %TITLETEXT% -- closing in %%as&PING.exe -n 2 -w 1 127.0.0.1>nul) 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy