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

Bra*_*ers 14 goto batch-file exit

我有一个简单的函数来检查目录:

: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
    )
Run Code Online (Sandbox Code Playgroud)

:结束写成

:end
endlocal
Run Code Online (Sandbox Code Playgroud)

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

:PRINT_USAGE
echo Usage:
echo ------
echo <file usage information>
goto:end
Run Code Online (Sandbox Code Playgroud)

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

jeb*_*jeb 17

我想你在这里混音callgoto陈述.

批处理文件中的标签可以与a call或a 一起使用goto,但行为不同.
如果你是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
Run Code Online (Sandbox Code Playgroud)

使用CTRL-C:

创建类似于CTRL-C错误代码的错误代码也会停止批处理.
退出后,setlocal状态是干净的!
请参阅@ dbenham的答案从函数内部退出批处理脚本

使用高级异常处理:

这是最强大的解决方案,因为它能够删除任意数量的堆栈级别,它可以用于仅退出当前批处理文件并显示堆栈跟踪.
它使用的事实是(goto),在没有参数的情况下,从堆栈中删除一个元素.
请参阅Windows批处理是否支持异常处理?

  • 除了无法返回到调用批处理脚本之外,此解决方案还可以防止在批量终止时发生的隐式ENDLOCAL,从而导致不必要的延迟环境更改. (3认同)

dbe*_*ham 5

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

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

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

更新2015-03-20 有关立即终止所有批处理的简洁方法,请参阅/sf/answers/1783225391/.

在函数中暂停批处理文件的另一种方法是使用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
Run Code Online (Sandbox Code Playgroud)

我的PC上有我的版本名为"daveExit.bat"和jeb的版本名为"jebExit.bat".

然后我使用这个批处理脚本测试它们

@echo off
echo before calling %1
call %1
echo returned from %1
Run Code Online (Sandbox Code Playgroud)

以下是结果

>test jebExit
before calling jebExit
hello
stop

>test daveExit
before calling daveExit
hello
stop
returned from daveExit

>
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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