17

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

nmake | tee output.txt
4

3 回答 3

29

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

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

问题在于 Windows 管道的工作机制。管道的每一侧都在它自己的 CMD shell 中执行。因此,一旦命令完成,您在那里设置的任何环境变量都会消失。%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 中:

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

上述两种解决方案都假定您正在批处理脚本中运行命令。如果您改为从命令行执行命令,则上述两种解决方案都需要
%^^errorlevel%而不是%%^^errorlevel%%.

但是鉴于nmake不需要用户输入,而且它通常很快,所以实时监控可能不是问题,那么最简单的解决方案似乎是

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


注意- 使用 Windows 管道时有许多微妙的复杂性。一个很好的参考是为什么在管道代码块中延迟扩展失败?. 我建议阅读问题和所有答案。所选答案具有最佳信息,但其他答案有助于提供上下文。

编辑 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=
于 2012-06-24T13:52:15.593 回答
3

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

nmake | mtee /E output.txt
于 2019-11-14T10:35:30.987 回答
1

受@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% 在执行时自动擦除。

于 2021-02-19T22:16:18.497 回答