如何将STDERRredirect到STDOUT,但忽略原始STDOUT?

我有一个STDERR输出的程序,我想检查和运行grep等。

所以我可以redirect到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

但是一定要有一个简单的方法来做到这一点?

什么不行:

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

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

不起作用,源于redirect的工作顺序的混乱。 您预计最后一次引用redirect将应用于每个输出之前的redirect,以便输出原始标准输出文件描述符(1)将转到/ dev / null,并输出到标准错误文件描述符(2)将去原来的标准输出。

但是,这不是shellredirect的工作方式。 每个redirect通过closures“源”并将“目的地”复制到其中(参见dup(2)close(2)mandup(2) ,使得文件描述符被“重新映射”。 这意味着在你的命令中,标准输出首先被replace为/dev/null ,然后将标准错误replace为标准输出,这已经是/dev/null了。

什么工作:

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

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

(注意1之前>是不必要的 – 对于输出redirect标准输出是默认的)


附录 :Charlie提到redirect到&-closures文件描述符。 如果使用支持该扩展的交互式shell( bash和其他一些实现,但不是全部,并且不是标准的 ),你也可以这样做:

 cmd 2>&1 >&- | grep pattern 

这可能会更好 – 它可以节省一些时间,因为当命令尝试写入标准输出时, write调用可能会立即失败,而不等待上下文切换到内核,并且驱动程序处理/dev/null (取决于系统调用实现 – 有些可能会在libc函数中捕获这个函数,有些可能还会为/dev/null特殊处理)。 如果有很多输出是值得的,input的速度会更快。

这大部分工作,因为大多数程序不关心,如果他们不写入标准输出(真正检查printf的返回值?),不会介意标准输出是封闭的。 但是如果write失败的话,一些程序可以用失败代码来救援 – 通常会阻塞处理器,使用一些小心的I / O库或logging到标准输出的程序。 所以,如果它不工作,请记住,这是一个可能的原因,并尝试/dev/null

先closuresSTDOUT:

 1>&-, >&- 

看到这里 。

我会尝试一些简单的:

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