如何从函数中退出批处理文件?

时间:2012-05-10 13:21:32

标签: batch-file exit goto

我编写了一个简单的函数来检查目录:

: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写为

:end
endlocal

我不明白为什么在调用goto:end之后程序不会停止。我有另一个函数使用相同的方法来停止程序,它工作正常。

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

在这种情况下,程序在调用后停止:end;为什么这不起作用:direxist?谢谢你的帮助!

4 个答案:

答案 0 :(得分:16)

我想你在这里混合callgoto语句。

批处理文件中的标签可以与callgoto一起使用,但行为不同。
如果您call这样的函数,它将在函数到达文件末尾或显式exit /bgoto :eof时返回(就像您的goto :end })。

因此,如果您将标签用作功能,则无法取消批次。

但是,goto标签不会返回给来电者。

使用synatx错误:

但也有一种方法可以从功能退出批次。
您可以创建语法错误,这会强制批处理停止 但它有副作用,即本地(setlocal)变量不会被删除。

@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

使用CTRL-C:

创建类似于CTRL-C错误代码的错误代码也会停止批处理 退出后,setlocal状态为 clean
请参阅@ dbenham的回答Exit batch script from inside a function

使用高级异常处理:

这是最强大的解决方案,因为它能够删除任意数量的堆栈级别,它可以用于仅退出当前批处理文件并显示堆栈跟踪。
它使用了这样一个事实,(goto),没有参数,从堆栈中删除一个元素 见Does Windows batch support exception handling?

答案 1 :(得分:6)

jeb的解决方案效果很好。但它可能并不适合所有情况。它有两个潜在的缺点:

1)语法错误将停止所有批处理。因此,如果批处理脚本调用了您的脚本,并且您的脚本因语法错误而停止,则控件不会返回给调用者。那可能不好。

2)当批处理终止时,通常每个SETLOCAL都有一个隐含的ENDLOCAL。但致命的语法错误终止批处理 而没有隐含的ENDLOCAL !这会产生令人讨厌的后果:-(有关详细信息,请参阅我的DosTips帖子SETLOCAL continues after batch termination!

更新2015-03-20 有关立即终止所有批处理的简洁方法,请参阅https://stackoverflow.com/a/25474648/1012053

在函数中暂停批处理文件的另一种方法是使用EXIT命令,该命令将完全退出命令shell。但是,对CMD的一点创造性使用可以使它有助于解决问题。

@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

我的电脑上有两个名为“daveExit.bat”的版本和名为“jebExit.bat”的jeb版本。

然后我使用这个批处理脚本

测试它们
@echo off
echo before calling %1
call %1
echo returned from %1

以下是结果

>test jebExit
before calling jebExit
hello
stop

>test daveExit
before calling daveExit
hello
stop
returned from daveExit

>

EXIT解决方案的一个潜在缺点是不会保留对环境的更改。这可以通过在退出之前将环境写入临时文件然后再读回来来部分解决。

@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

但值中带有换行符(0x0A)的变量将无法正确保存。

答案 2 :(得分:2)

如果您使用exit /b X退出该功能,则会将ERRORLEVEL设置为X的值。然后,如果||非零,您可以使用ERRORLEVEL conditional processing symbol执行命令。

@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

此脚本的输出是:

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

答案 3 :(得分:1)

这是我的解决方案,如果检查了所有错误级别,它将支持嵌套例程 我在所有电话(内部或外部)

中添加了errolevel测试
@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