tags:

views:

856

answers:

2

Hi.

I've got a windows batch file, with a few sub-routines in it something like this:

call :a
goto :eof

:a
call :b
goto :eof

:b
:: How do I directly exit here from here?
goto :eof

I'm running this in a cmd window on Vista.
If I detect an error somewhere in the batch file, I want it to exit with a non-zero errorlevel. Is there anything I can write in the routine :b that will cause the batch file to terminate like this.

  • I've tried 'exit', which closes the entire cmd window. That's not what I want.
  • I've tried 'exit /B 1'. That returns to the previous routine. To use this scheme after every 'call' I'd have to carefully write 'if errorlevel 1 exit /B 1' after every single 'call' to pass the error back up the call stack. I'd prefer not to have to write this line after every call.

This article was interesting, but non of the alternatives behave in the way I want. http://www.computerhope.com/exithlp.htm

Is there another way?

Thanks.

+4  A: 

You can call your subroutines like so:

call :b||exit /b 1

which is equivalent to

call :b
if errorlevel 1 exit /b 1

It's slightly shorter and saves you one line, but it's still not ideal, I agree.

Other than that I don't see a way.

EDIT: Ok, I got a way, but it's Pure Evil™.

Misusing the maximum stack size, and therefore recursion limit, we create another subroutine which simply exhausts the stack by recursively calling itself:

@echo off
echo Calling a
call :a
echo Called a
goto :eof
:a
echo Calling b
call :b
echo Called b
goto :eof
:b
echo Trying to exit
call :exit
goto :eof
:exit
call :exit

This, however, will result in the nasty error message

******  B A T C H   R E C U R S I O N  exceeds STACK limits ******
Recursion Count=704, Stack Usage=90 percent
******       B A T C H   PROCESSING IS   A B O R T E D      ******

Also, it will take around 2 seconds on my machine.

You can suppress the error message by altering the call statement as follows:

call :exit >nul 2>&1

which will redirect everything it wants to output into a great void.

But considering the time it takes to fill the stack I think the first variant would be easier.

I was also contemplating using a second batch file, which, when run without call would essentially stop the first one. But somehow that doesn't play well with subroutines. Unrolling the call stack seemingly still takes place.

Joey
Cool, thanks. This is the best so far. From this I found if I use "call :a || goto :eof", then the errorlevel will be propagated back up. Useful if the specific errorlevel has some usable meaning.
Scott Langham
Yes, that sounds indeed better. Didn't think of it. Also, the recursive abort I outlined isn't a real option, I suppose :)
Joey
Yes, the recursive abort was novel, but just a bit too far out there! :)
Scott Langham
A: 

You could create an exit.bat file that kills the the top bat file by title name.

Example:

A.bat

@echo off
title A.bat
echo A.bat
call B.bat
echo A.bat

B.bat

@echo off
echo B.bat
exit.bat A.bat
echo B.bat

Exit.bat

@echo off
echo exit.bat
kill %1
Jeremy E
while definitely cool and definitely evil, this approach will get rid of the complete cmd process. Which is exactly what exit would do and which the OP didn't consider acceptable. Also, kill would have to be replaced by taskkill /fi "windowtitle -eq %1" since there is no kill command on Windows.
Joey
Ah I forgot I installed "Debugging Tools for Windows" (WinDbg) and it includes a copy of kill.exe. Thanks for the taskkill command I didn't realize it was there.
Jeremy E
To make the pain of killing the whole window less well painful you could always use the start cmd a.bat to fire off the part you want to kill.
Jeremy E