【问题标题】:Is there a way to redirect ONLY stderr to stdout (not combine the two) so it can be piped to other programs?有没有办法仅将 stderr 重定向到 stdout(而不是将两者结合起来),以便可以通过管道传输到其他程序?
【发布时间】:2012-08-29 17:25:24
【问题描述】:

我在 Windows CMD.EXE 环境中工作,并希望更改 stdout 的输出以匹配 stderr 的输出,这样我就可以在没有文件中介的情况下将错误消息传递给其他程序。

我知道2>&1 表示法,但它将stdoutstderr 组合成一个流。

我的想法是这样的:

program.exe 2>&1 | find " "

但这结合了标准输出和标准错误,就像:

program.exe | find " " 2>&1

我意识到我可以做到……

program 2>file
type file | find " "
del file

但这不具备program | find " " 那种符号的灵活性和强大功能。这样做需要program 完成其输出,然后才能处理该输出。

【问题讨论】:

    标签: windows batch-file


    【解决方案1】:

    有趣的问题:-)

    CMD 处理从左到右的重定向。您想首先将 2 (stderr) 重定向到 &1 (stdout),然后将 1 (stdout) 重定向到其他东西。此时stderr仍将被重定向到之前的stdout定义。管道仍然可以使用标准输出的旧定义(现在包含标准错误)。

    如果你不关心标准输出,那么你可以重定向到 nul

    program.exe 2>&1 1>nul | find " "
    


    如果您想将标准输出捕获到文件然后重定向到文件

    program.exe 2>&1 1>yourFile | find " "
    


    如果您仍想在控制台上看到 stdout,但您只想将 stderr 传送到 FIND,那么您可以将 1 重定向到 con:

    program.exe 2>&1 1>con: | find " "
    

    请注意,stdout 和 con: 的原始定义之间存在细微差别。例如,cls >con: 不清除屏幕,而是在屏幕上打印一个有趣的字符。

    如果您使用第三个(最初未使用的)文件句柄,则可以真正交换 stdout 和 stderr。 1 和 3 将包含 stderr 的原始定义,2 将包含 stdout 的原始定义。

    program.exe 3>&2 2>&1 1>&3 | find " "
    

    实际上,每次执行重定向时都会定义一个额外的文件句柄。原始定义保存在第一个可用的未使用文件句柄中。假设在发出上述命令之前没有任何重定向。 3>&2 不保存 3 的原始定义,因为之前没有定义 3。但是2>&1将stderr的原定义保存在4中(3已经用过),1>&2将stdout的原定义保存在5中。

    所以从技术上讲,交换stderr和stdout不需要3的显式重定向

    program.exe 2>&1 1>&3 | find " "
    

    2>&1 将 stderr 保存在 3 中,并将 2 重定向到 &1 (stdout)。 1>&3 将 stdout 保存在 4 中,并且 1 被重定向到 &3 (stderr)。

    但只有在您确定在发出命令之前尚未定义 3 时,上述操作才能正常工作。在我之前的代码示例中明确定义 3 会更安全。

    请参阅Why doesn't my stderr redirection end after command finishes? And how do I fix it?,了解一些非常疯狂的重定向冒险:-)

    【讨论】:

    • @JamesK - 添加了另一个可能比使用 con: 更强大的选项:
    • 但对我来说,3>&2 2>&1 1>&32>&1 1>&3 结合了 stdoutstderr
    • @JamesK - 真的吗?它适用于 Vista 和 Windows 7。我没有机会检查 XP。 DIR DoesNotExist 2>&1 1>&3 | FIND "" 将空目录列表传递到屏幕但删除错误消息,而DIR DoesNotExist 2>&1 1>&3 | FIND /V "" 将空目录列表和错误消息都传递。
    • DIR DoesNotExist 2>&1 1>&3 | FIND "" 确实删除了错误消息,而 ... | find " " 显示了两者。我假设DIR DoesNotExist 2>&1 1>&3DIR DoesNotExist 2>&1 1>&3 | find " " 相同,因为DIR DoesNotExist 2>&1 1>nul 有效。另外,我不确定stderr=="" 是如何工作的,所以我不明白... | find "" 是如何工作的。 (我使用的是 Windows 7 Ultimate x64。)
    • @JamesK - 我认为您的问题可能与您的测试有关。 ... | FIND " " 将匹配任何包含空格的行。 ... | FIND /V "" 是一个匹配所有行的 FIND 怪癖——我一直不明白为什么,但它很有用。 ... | FIND "" 不会匹配任何行。我选择了这些表单,以便我可以验证 stderr 是否正在通过管道传输而 stdout 没有。
    【解决方案2】:

    http://support.microsoft.com/kb/110930 看来,您似乎想要2>&1 1>NUL。因此,以下内容应该适合您:

    test.exe 2>&1 1>NUL | find "someErrorString"
    

    【讨论】:

      猜你喜欢
      • 2013-05-21
      • 2022-01-18
      • 2020-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-12
      • 2014-07-22
      相关资源
      最近更新 更多