如何将STDERR重定向到STDOUT,但忽略原始STDOUT?

时间:2009-02-14 20:27:27

标签: bash redirect stdout

我有一个程序,我希望检查STDERR输出并运行grep等。

所以我可以将其重定向到STDOUT并使用grep,但问题是,我想要原始的STDOUT内容。

所以,这个不会做

cmd 2>&1 | grep pattern

因为它会混合原始的STDOUT和STDERR。

这个不起作用,因为grep没有读取STDERR输出:

cmd 1>/dev/null | grep pattern

但是,这个也行不通:

cmd 1>/dev/null 2>&1 | grep pattern

因为输出将完全为空,因为所有内容都会写入/dev/null

但必须有一个简单的方法吗?

3 个答案:

答案 0 :(得分:98)

什么行不通:

你引用的最后一个命令的原因:

cmd 1>/dev/null 2>&1 | grep pattern

不起作用,源于对重定向工作顺序的混淆。您希望最后引用的重定向应用于每个输出之前的重定向,以便输出原始标准输出文件描述符(1)将转到/ dev / null,并输出到标准错误文件描述符(2)将转到原始标准输出。

但是,这不是shell重定向的工作原理。每次重定向都会通过关闭“源”并将“目标”复制到其中来“重新映射”文件描述符(请参阅mandup(2)的{​​{1}}页面) 。这意味着在您的命令中,标准输出首先被close(2)替换,然后标准错误替换为标准输出,已经/dev/null

什么有效:

因此,要获得所需的效果,您只需要反转重定向。然后您将标准错误转到标准输出,原始标准输出转到/dev/null

/dev/null

(请注意,cmd 2>&1 >/dev/null | grep pattern 之前的1是不必要的 - 对于输出重定向标准输出是默认值)


附录:Charlie提到重定向到>以关闭文件描述符。如果使用支持该扩展的交互式shell(&-和其他一些实现但不是全部而且它是not standard),您也可以这样做:

bash

这可能会更好 - 它可以节省一些时间,因为当命令尝试写入标准输出时,对cmd 2>&1 >&- | grep pattern 的调用可能会立即失败,而无需等待上下文切换到内核并且驱动程序处理{{ 1}}(取决于系统调用实现 - 有些可能会在write函数中捕获这个,有些可能还会对/dev/null进行特殊处理)。如果有很多输出是值得的,那么键入的速度会更快。

这主要是因为大多数程序都不关心它们是否无法写入标准输出(谁真正检查libc的返回值?)并且不介意标准输出被关闭。但是如果/dev/null失败,一些程序可以使用失败代码进行挽救 - 通常会阻止处理器,程序使用一些仔细的I / O库或记录到标准输出。因此,如果它不起作用,请记住这可能是原因并尝试printf

答案 1 :(得分:3)

首先关闭STDOUT:

1>&-, >&-

请参阅here

答案 2 :(得分:-4)

我会尝试一些简单的事情:

cmd 2> tmp_file && cat tmp_file | grep pattern && rm -f tmp_file