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

Windows命令解释器:如何获取第一个管道命令的退出代码,windows,cmd,pipe,exit-code,Windows,Cmd,Pipe,Exit Code,在下面提供的示例中,我执行nmake,然后将STDOUT/STDERR重定向到tee,tee随后将其发送到屏幕,以及一个日志文件。 问题是,我试图捕获nmake而不是tee的退出代码。 我需要的是nmake的退出代码,而不是tee nmake | tee output.txt 你可能认为你可以做如下的事情,但这是行不通的 (nmake & call set myError=%%errorlevel%%) | tee output.txt 问题在于Windows管道的工作机制。管道的每

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

nmake | tee output.txt

你可能认为你可以做如下的事情,但这是行不通的

(nmake & call set myError=%%errorlevel%%) | tee output.txt
问题在于Windows管道的工作机制。管道的每一侧都在它自己的CMD shell中执行。因此,在那里设置的任何环境变量都将在命令完成后消失。另外,由于额外的解析级别,以及CMD shell具有命令行上下文而不是批处理上下文,因此%errorlevel%的延迟扩展更加复杂

你可以这样做:

(nmake & call echo %%^^errorlevel%% ^>myError.txt) | tee output.txt
for /f %%A in (myError.txt) do echo nmake returned %%A
del myError.txt
或者可以将errorlevel嵌入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,而无需求助于临时文件。我是从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
如果需要,可以在末尾添加另一个命令,以在检索值后清除err“macro”的定义

doskey /exename=err err=
有一个版本的“tee”(称为mtee=>)可以选择采用管道流程的退出代码。这样你就可以写作了

nmake | mtee /E output.txt

受@dbenham答案的启发,我制作了以下版本:

(%cmd% & call echo EXIT /B %^^ERRORLEVEL% >%ret_file%)
      | tee %log_file% & %ret_file%>NUL
它是一个单行程序,可以在命令行或批处理文件中使用。 它的优点是该行最终生成正确的%ERRORLEVEL%, 所以你可以用传统的方法来评估它

  • 执行命令%cmd%,将%ERRORLEVEL%设置为我们需要检索的值
  • 我们正在使用调用机制来获得手动延迟扩展(因此我们得到了%ERRORLEVEL%的正确值)。该调用将创建一个小命令作为批处理文件%ret_file%),该批处理文件以与原始命令%cmd%相同的%ERRORLEVEL%退出
  • 管道执行它需要执行的任何操作,然后执行mini命令%ret_file%,将%ERRORLEVEL%设置为适当的值
  • 缺点是,一行程序会在目录中留下包含

    EXIT /B <some_error_value>
    
    退出/B
    

    您可以轻松地调整一行程序,使脚本%ret_file%在执行时自动擦除。

    简单的解决方案解决了使用tee(同步输出)的主要原因。同样,对于您可以使用的第一个解决方案“set/p MY_ERROR=如何处理
    呼叫设置
    呼叫回音
    等等?我以前从未见过这种语法。@Alek-在初始解析后进行第二轮变量扩展是一种老生常谈。它是使用延迟扩展的替代方案<代码>回声!瓦尔类似于调用echo%%var%%。延迟扩展通常是首选,但有时需要调用hack。如果有人想尝试第一个“或者您可以将errorlevel嵌入到您的output.txt”示例,则无需编写批处理文件,您必须执行以下操作
    (echo exit…&cmd/c exit/b 1234&call echo%^^errorlevel%>myerror.txt)| tee file.txt
    ,因为在批处理文件中,百分比只会翻倍以转义。另外,@dbenham,我很困惑,因为你说“DOSKEY宏不能通过批处理执行”但是后来看到你在这个例子中把百分比翻了一倍,这让它看起来像你可以。这特别奇怪,因为..如果你不能在批处理文件中使用它们,那么这个例子怎么会有用呢?…我最终意识到你的意思是你可以在批处理文件中使用它,因为你只是定义它,而不是执行它,并且他最后给出了定义。我真的不知道如何更好地表达这一点,但我想知道,如果没有doskey知识,这可能会让人困惑。=/似乎不适合我C:\Temp>C:\Python26\python.exe t.py | h:\apps\mtee/E out3.txt C:\Temp>echo%ERRORLEVEL%0 C:\Temp>more t.py import sys.exit(1)C:\Temp>h:\apps\mtee/?mtee v2.21适用于Windows XP的Win32命令行标准流拆分器..10.版权所有(C)2001-2016 Ritchie Lawrence