Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I exit a batch file from within a function?

I have a simple function written to check for directories:

:direxist
if not exist %~1 (
    echo %~1 could not be found, check to make sure your location is correct.
    goto:end
    ) else (
    echo %~1 is a real directory
    goto:eof
    )

:end is written as

:end
endlocal

I don't understand why the program would not stop after goto:end has been called. I have another function that uses the same method to stop the program and it work fine.

:PRINT_USAGE
echo Usage:
echo ------
echo <file usage information>
goto:end

In this instance, the program is stopped after calling :end; why would this not work in :direxist? Thank you for your help!

like image 579
Brad Conyers Avatar asked May 10 '12 13:05

Brad Conyers


People also ask

How do you exit a batch file?

EXIT /B at the end of the batch file will stop execution of a batch file. use EXIT /B < exitcodes > at the end of the batch file to return custom return codes.

How do I stop a script from command line?

Ctrl+C. One of the most universal methods of aborting a batch file, command, or another program while it's running is to press and hold Ctrl + C . This keyboard shortcut sends a SIGINT signal, which cancels or terminates the currently-running program and returns you to the command line.

How do I close a batch file without closing the window?

Batch file processing ends when execution reaches the end of the batch file. The trick therefore is to use the goto command to jump to a label right before the end of the file, so that execution “falls off the end”.

What is %% f in batch file?

For simple batch files, a single character such as %%f will work. You can use multiple values for variable in complex batch files to distinguish different replaceable variables.


2 Answers

I suppose you are mixing call and goto statements here.

A label in a batch file can be used with a call or a goto, but the behaviour is different.
If you call such a function it will return when the function reached the end of the file or an explicit exit /b or goto :eof (like your goto :end).

Therefore you can't cancel your batch if you use a label as a function.

However, goto to a label, will not return to the caller.

Using a synatx error:

But there is also a way to exit the batch from a function.
You can create a syntax error, this forces the batch to stop.
But it has the side effect, that the local (setlocal) variables will not be removed.

@echo off
call :label hello
call :label stop
echo Never returns
exit /b

:label
echo %1
if "%1"=="stop" goto :halt
exit /b

:halt
call :haltHelper 2> nul

:haltHelper
() 
exit /b

Using CTRL-C:

Creating an errorcode similar to the CTRL-C errorcode stops also the batch processing.
After the exit, the setlocal state is clean!
See @dbenham's answer Exit batch script from inside a function

Using advanced exception handling:

This is the most powerful solutions, as it's able to remove an arbitrary amount of stack levels, it can be used to exit only the current batch file and also to show the stack trace.
It uses the fact, that (goto), without arguments, removes one element from the stack.
See Does Windows batch support exception handling?

like image 51
jeb Avatar answered Sep 21 '22 22:09

jeb


jeb's solution works great. But it may not be appropriate in all circumstances. It has 2 potential drawbacks:

1) The syntax error will halt all batch processing. So if a batch script called your script, and your script is halted with the syntax error, then control is not returned to the caller. That might be bad.

2) Normally there is an implicit ENDLOCAL for every SETLOCAL when batch processing terminates. But the fatal syntax error terminates batch processing without the implicit ENDLOCAL! This can have nasty consequences :-( See my DosTips post SETLOCAL continues after batch termination! for more information.

Update 2015-03-20 See https://stackoverflow.com/a/25474648/1012053 for a clean way to immediately terminate all batch processing.

The other way to halt a batch file within a function is to use the EXIT command, which will exit the command shell entirely. But a little creative use of CMD can make it useful for solving the problem.

@echo off
if "%~1" equ "_GO_" goto :main
cmd /c ^""%~f0" _GO_ %*^"
exit /b

:main
call :label hello
call :label stop
echo Never returns
exit /b

:label
echo %1
if "%1"=="stop" exit
exit /b

I've got both my version named "daveExit.bat" and jeb's version named "jebExit.bat" on my PC.

I then test them using this batch script

@echo off
echo before calling %1
call %1
echo returned from %1

And here are the results

>test jebExit
before calling jebExit
hello
stop

>test daveExit
before calling daveExit
hello
stop
returned from daveExit

>

One potential disadvantage of the EXIT solution is that changes to the environment are not preserved. That can be partially solved by writing the environent to a temporary file before exiting, and then reading it back in.

@echo off
if "%~1" equ "_GO_" goto :main
cmd /c ^""%~f0" _GO_ %*^"
for /f "eol== delims=" %%A in (env.tmp) do set %%A
del env.tmp
exit /b

:main
call :label hello
set junk=saved
call :label stop
echo Never returns
exit /b

:label
echo %1
if "%1"=="stop" goto :saveEnvAndExit
exit /b

:saveEnvAndExit
set >env.tmp
exit

But variables with newline character (0x0A) in the value will not be preserved properly.

like image 33
dbenham Avatar answered Sep 20 '22 22:09

dbenham