Windows命令解释器:如何获取第一个管道命令的退出代码

时间:2012-06-23 15:36:30

标签: windows cmd pipe exit-code

在下面提供的示例中,我执行nmake,然后将STDOUT / STDERR重定向到tee,然后将其发送到屏幕,还发送到日志文件。 问题是我正在尝试捕获nmake的退出代码而不是tee。 我需要的是nmake的退出代码,而不是tee。

nmake | tee output.txt

3 个答案:

答案 0 :(得分:27)

您可能认为自己可以执行以下操作,但不起作用。

(nmake & call set myError=%%errorlevel%%) | tee output.txt

问题在于Windows管道的工作机制。管道的每一侧都在它自己的CMD外壳中执行。因此,在命令完成后,您在此处设置的任何环境变量都将消失。此外,%errorlevel%的延迟扩展更复杂,因为解析的额外级别,并且因为CMD shell具有命令行上下文而不是批处理上下文。

你可以这样做:

(nmake & call echo %%^^errorlevel%% ^>myError.txt) | tee output.txt
for /f %%A in (myError.txt) do echo nmake returned %%A
del myError.txt

或者你可以在你的output.txt中嵌入errorlevel:

(nmake & call echo nmakeReturnCode: %%^^errorlevel%%) | tee output.txt
for /f "tokens=2" %%A in ('findstr /b "nmakeReturnCode:" output.txt') do echo nmake returned %%A

但最简单的解决方案似乎是

nmake >output.txt
set myError=%errorlevel%
type output.txt
echo nmake returned %myError%


注意 - 使用Windows管道时会有许多细微的复杂情况。一个很好的参考是Why does delayed expansion fail when inside a piped block of code?。我建议阅读问题和所有答案。所选答案具有最佳信息,但其他答案有助于提供上下文。

编辑2015-06-02

我最近发现您可以使用DOSKEY宏从管道的任一侧(或两侧)干净地存储和检索ERRORLEVEL,而无需使用临时文件。我从http://www.dostips.com/forum/viewtopic.php?p=41409#p41409的DosTips用户Ed Dyreen那里得到了这个想法。 DOSKEY宏不能通过批处理执行,但是在ENDLOCAL和CMD / C退出后,定义仍然存在!

以下是在您的情况下如何使用它:

(nmake & call doskey /exename=err err=%%^^errorlevel%%) | tee output.txt
for /f "tokens=2 delims==" %%A in ('doskey /m:err') do echo nmake returned %%A

如果需要,可以在结束时再添加一个命令,以在检索到值后清除错误“宏”的定义。

doskey /exename=err err=

答案 1 :(得分:2)

有一个“ tee”版本(称为mtee => https://ritchielawrence.github.io/mtee/),可以选择采用管道处理的退出代码。这样你就可以写

nmake | mtee /E output.txt

答案 2 :(得分:0)

受到@dbenham 回答的启发,我做了以下版本:

(%cmd% & call echo EXIT /B %^^ERRORLEVEL% >%ret_file%)
      | tee %log_file% & %ret_file%>NUL

它是单行的,可以在命令行或批处理文件中使用。 它的优点是该行最终产生正确的 %ERRORLEVEL%, 所以你可以用传统的方式来评估它。

  1. 执行命令 %cmd%,将 %ERRORLEVEL% 设置为我们需要检索的值。
  2. 我们使用 CALL 机制来获得手动延迟扩展(因此我们获得了正确的 %ERRORLEVEL% 值)。该调用创建了一个作为批处理文件 %ret_file%) 的小命令,该小命令以与原始命令 %cmd% 相同的 %ERRORLEVEL% 退出。
  3. 管道执行它需要做的任何事情,然后执行迷你命令 %ret_file%,将 %ERRORLEVEL% 设置为适当的值。

缺点是单行代码会用包含少量文件的目录乱丢

EXIT /B <some_error_value>

您可以轻松调整单行,以便脚本 %ret_file% 在执行时自动擦除。