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

前端 未结 4 479
自闭症患者
自闭症患者 2020-12-28 08:33

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          


        
相关标签:
4条回答
  • 2020-12-28 08:48

    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?

    0 讨论(0)
  • 2020-12-28 08:53

    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.

    0 讨论(0)
  • 2020-12-28 08:59

    If you use exit /b X to exit from the function then it will set ERRORLEVEL to the value of X. You can then use the || conditional processing symbol to execute a command if ERRORLEVEL is non zero.

    @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
    

    Output from this script is:

    myfunction: Everything is good.
    myfunction: got a FAIL. Will exit.
    
    0 讨论(0)
  • 2020-12-28 08:59

    Here's my solution that will support nested routines if all are checked for errorlevel I add the test for errolevel at all my calls (internal or external)

    @echo off
    call :error message&if errorlevel 1 exit /b %errorlevel%<
    @echo continuing
    exit /b 0
    :error
    @echo in %0
    @echo message: %1
    set yes=
    set /p yes=[no]^|yes to continue
    if /i "%yes%" == "yes" exit /b 0
    exit /b 1
    
    0 讨论(0)
提交回复
热议问题