如何在“call”子程序中终止Windows批处理文件?

9

我有一个Windows批处理文件,其中包含几个子程序,类似于以下内容:

call :a
goto :eof

:a
call :b
goto :eof

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

我正在Vista的cmd窗口中运行此程序。如果我在批处理文件中检测到错误,我希望它以非零错误级别退出。在:b例程中是否有任何可以使批处理文件像这样终止的内容?
  • 我尝试了'exit',它关闭了整个cmd窗口。那不是我想要的。
  • 我尝试了'exit /B 1'。它返回到上一个例程。为了在每个“call”后使用此方案,我必须仔细编写“if errorlevel 1 exit /B 1”,以将错误传递回调用堆栈。我宁愿不在每个调用后编写此行。

本文很有趣,但是没有一种替代方案能够按照我想要的方式运行。 http://www.computerhope.com/exithlp.htm

还有其他方法吗?

谢谢。

2个回答

17
你可以这样调用你的子程序:

call :b||exit /b 1

等价于

call :b
if errorlevel 1 exit /b 1

稍微更短一些,可以省略一行代码,但我同意这仍然不是理想的。

除此之外,我没有其他的办法。

编辑:好吧,我找到了一种方法,但它是“纯邪恶”的。

滥用最大堆栈大小(因此也是递归限制),我们创建另一个子例程,通过递归调用自身来耗尽堆栈:

@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

然而,这将导致一个令人不快的错误消息:

****** 批处理递归超过了堆栈限制 ******
递归计数=704,堆栈使用率=90%
******    批处理处理被终止   ******

此外,在我的电脑上需要大约2秒钟。

您可以通过修改call语句来取消显示错误消息,具体如下:

call :exit >nul 2>&1

这将把所有输出重定向到一个巨大的虚无中。

但考虑到填充堆栈需要的时间,我认为第一种变体会更容易。

我还在考虑使用第二个批处理文件,当没有使用call时,它可以停止第一个批处理文件。但不知何故,这与子例程不太兼容。展开调用堆栈似乎仍然会发生。


4
太棒了,谢谢。这是迄今为止最好的方案。从中我发现如果我使用“call :a || goto :eof”,则错误级别将被传回。如果特定的错误级别具有可用意义,则非常有用。 - Scott Langham
是的,这听起来确实更好。我没有想到。另外,我勾画的递归中止不是一个真正的选择,我想 :) - Joey
是的,递归中止很新颖,但有点太过了! :) - Scott Langham

0
你可以创建一个 exit.bat 文件,通过标题名称杀死顶部的 bat 文件。
示例:

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

1
虽然这种方法绝对很酷,但也绝对很邪恶,它将摆脱完整的cmd进程。这正是exit所做的,而OP认为这是不可接受的。此外,kill必须被taskkill /fi "windowtitle -eq %1"替换,因为Windows上没有kill命令。 - Joey
啊,我忘记了我安装了“Windows调试工具”(WinDbg),它包含一个kill.exe的副本。感谢taskkill命令,我没意识到它在那里。 - Jeremy E
为了减轻关闭整个窗口的痛苦,您可以使用start cmd a.bat来启动您想要关闭的部分。 - Jeremy E

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接