在带有其他命令的块内时退出 /b 无法正常工作

Posted

技术标签:

【中文标题】在带有其他命令的块内时退出 /b 无法正常工作【英文标题】:exit /b not working correctly when inside a block with other commands 【发布时间】:2016-03-17 13:39:20 【问题描述】:

我有一个需要在 32 位上下文中运行的批处理文件,因此包含一些代码以使用自己的路径调用 32 位命令处理器。该脚本还需要能够在失败时返回错误代码,它通过exit /b 123 执行。但是... 当 exit 位于 ( ) 块中时,并且在其后包含任何语句,则不会正确返回。

@echo off
setlocal EnableDelayedExpansion

rem Ensure we're running in 32-bit mode
if not %PROCESSOR_ARCHITECTURE%==x86 (
  echo Thunking to 32-bit mode
  %Windir%\SysWOW64\cmd.exe /c %0
  echo !ERRORLEVEL!
  exit /b !ERRORLEVEL!
)

(
  echo before
  exit /b 456
  echo after
)

输出如下:

H:\>sub.bat
Thunking to 32-bit mode
before
0

H:\>

如果您在exit 之后删除echo,那么它的工作方式与预期完全一样。

H:\>sub.bat
Thunking to 32-bit mode
before
456

H:\>

即使您将echo 替换为rem 或任何其他命令,它仍然会失败。如果您手动运行 32 位 cmd.exe 并运行相同的脚本,则退出代码设置正确。

H:\>sub.bat
before

H:\>echo %ERRORLEVEL%
456

H:\>

谁能对此给出解释和解决方法?

【问题讨论】:

%Windir%\SysWOW64\cmd.exe /c %0 ^& exit %%%%errorlevel%%%% 应该也可以工作(我对亚当回答的评论的附录)。 【参考方案1】:

在脚本的“else”部分使用 /b 开关导致退出代码被 cmd.exe 的第二个实例丢失。

当批处理文件的第二个实例从 Syswow64 执行时,它将以代码 456 退出。其父 cmd.exe 将收到此退出代码,但没有兴趣保留它。 cmd.exe 能够成功运行批处理,因此以 0 退出,返回到第一个实例。

如果您在脚本的“else”部分省略 /b 开关,这将强制批处理文件退出其父 cmd.exe,而不仅仅是完成处理。由于 cmd.exe 然后被告知以 456 退出代码退出,这将被保留。

“exit”的帮助文本确实可以推断出这种行为,但在您牢记这一点之前,它似乎并不十分明显!

【讨论】:

虽然从后者 exit 中删除 /b 是可行的,但它还有其他影响,例如如果直接从 32 位运行退出命令提示符,以及任何调用批处理脚本。此外,第二个块通常在更多代码之后并且有自己的条件,但在本示例中被剥离。 @Deanna - 既然如此,为什么不在您的 SysWOW 调用 (%Windir%\SysWOW64\cmd.exe /c %0 /B) 中传递一个参数。然后在您的“其他”条件下使用:exit %1 456。如果没有递归调用,%1 将为空:exit 456 很好的解释! +1(这是您在此论坛的第一个答案)欢迎! :) @Jason,错误的方式,我们需要 /B 当它不是递归调用而不是当它是。尽管如此,仍然很容易完成。环境变量可能比参数更可取,以获得最大的灵活性。就个人而言,我建议批处理文件 always 在子进程中运行,而不管当前命令处理器的位数如何。 (您可以设置参数或环境变量来防止无限递归。) 您说的是else 部分,但我在问题中找不到任何else 关键字...

以上是关于在带有其他命令的块内时退出 /b 无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

为啥退出在功能命令中不起作用如何使其工作?

退出框架时卸载 swf

Visual Studio Autodeploy - nuget命令失败,退出代码和错误NU1102

为啥实例变量在块内时似乎消失了?

vim快捷键

发布 ASP.NET 核心应用程序:命令“npm install”退出,代码为 9009