65

我有一个程序,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.

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

4

3 回答 3

113

什么不起作用:

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

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

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

但是,这不是 shell 重定向的工作方式。每个重定向都会导致文件描述符被“重新映射”,方法是关闭“源”并按顺序将“目标”复制到其中(参见 和 的页面man)。这意味着在您的命令中,标准输出首先被替换为,然后标准错误被替换为标准输出,这已经是。dup(2)close(2)/dev/null/dev/null

什么有效:

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

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

(注意1之前>是不必要的 - 对于输出重定向标准输出是默认的)


附录:查理提到重定向&-到关闭文件描述符。如果使用支持该扩展的交互式外壳(bash以及其他一些实现,但不是全部,它不是标准的),您也可以这样做:

cmd 2>&1 >&- | grep pattern

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

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

于 2009-02-14T20:45:47.703 回答
4

先关闭 STDOUT:

1>&-, >&-

这里

于 2009-02-14T20:31:32.620 回答
-4

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

cmd 2> tmp_file && cat tmp_file | grep pattern && rm -f tmp_file
于 2009-02-14T20:33:36.483 回答