How can I redirect STDERR to STDOUT, but ignore the original STDOUT?
我有一个程序,其STDERR输出我想检查并运行grep等。
所以我可以将它重定向到STDOUT并使用grep,但问题是,我不想要原始的STDOUT内容。
所以,这个不会做
因为它会混合原始的STDOUT和STDERR。
而且这个不起作用,因为grep没有读取STDERR输出:
1
| cmd 1>/dev/null | grep pattern |
但是,这个也行不通:
1
| cmd 1>/dev/null 2>&1 | grep pattern |
因为输出将完全为空,因为所有内容都写入/dev/null。
但必须有一个简单的方法来做到这一点?
什么行不通:
你引用的最后一个命令的原因:
1
| cmd 1>/dev/null 2>&1 | grep pattern |
不起作用,源于对重定向工作顺序的混淆。您希望最后引用的重定向应用于每个输出之前的重定向,以便输出原始标准输出文件描述符(1)将转到/ dev / null,并输出到标准错误文件描述符(2)将转到原始标准输出。
但是,这不是shell重定向的工作原理。每次重定向都会导致文件描述符被"重新映射",方法是关闭"源"并将"目标"复制到其中(参见man和close(2)的man页面)。这意味着在您的命令中,标准输出首先替换为/dev/null,然后标准错误替换为标准输出,已经是/dev/null。
什么有效:
因此,要获得所需的效果,您只需要反转重定向。然后你会有标准错误转到标准输出,原始标准输出转到/dev/null:
1
| cmd 2>&1 >/dev/null | grep pattern |
(注意>之前>是不必要的 - 输出重定向标准输出是默认值)
附录:Charlie提到重定向到&-以关闭文件描述符。如果使用支持该扩展的交互式shell(bash和其他一些实现但不是全部,并且它不是标准的),您也可以这样做:
1
| cmd 2>&1 >&- | grep pattern |
这可能会更好 - 它可以节省一些时间,因为当命令尝试写入标准输出时,对write的调用可能会立即失败而无需等待上下文切换到内核并且驱动程序处理/dev/null(取决于系统调用实现 - 有些可能会在libc函数中捕获这个,有些也可能对/dev/null进行特殊处理。如果有很多输出是值得的,那么键入的速度会更快。
这将主要起作用,因为大多数程序不关心它们是否无法写入标准输出(谁真正检查printf的返回值?)并且不介意关闭标准输出。但是如果write失败,一些程序可以使用失败代码进行救援 - 通常会阻止处理器,程序使用一些仔细的I / O库或记录到标准输出。因此,如果它不起作用,请记住这可能是原因并尝试/dev/null。
首先关闭STDOUT:
看这里。
-
嗯,你确定会做OP想要的吗?似乎不适合我。如果先关闭stdout,则无法将stderr重定向到它。
-
好的,基于此,我发现这有效:2>& 1>& - 。也许您可以更新答案,因为它目前正在编写,可能会尝试这样:>& - 2>& 1,这不起作用。
-
是的,那种方式(在重定向后关闭它)它的工作原理,并且支持有时比使用/ dev / null更好,因为你节省写入 - 我会更新我的答案提及。请注意,这是一些shell(包括bash)支持的扩展,但在sh中显然不是标准的。
-
关闭stdout,而不是发送到/ dev / null,只有在写入stdout的命令忽略写入错误时才有效 - 这是对C编程的悲伤评论,事实上,大多数情况下,程序会忽略这些错误。
-
毕竟你确实将它标记为bash。
-
@Jonathan Leffler - 正如我所提到的那样 - 如果命令实际上对写入错误有效,则关闭stdout将不起作用。然而,正如你所提到的,大多数C程序都没有。我总是试图检查错误,如果只是打印消息,我通常不检查printf的输出。伤心?不
-
@Charlie Martin。是的,它被标记为bash,答案可能很好。我不太了解bash的扩展,所以我实际上在这里学到了一些东西:-)
-
@Jonathan Leffler - 至于忽略写入的返回 - 当写入"重要"(对运行有影响)时,我当然同意必须检查错误。但是对于通常的输出 - 考虑当管道到头时会发生什么,例如,如果你的程序在stdout关闭时失败了。
我会尝试一些简单的事情:
1
| cmd 2> tmp_file && cat tmp_file | grep pattern && rm -f tmp_file |
-
所选答案表明这是不必要的。你在第二部分中使用猫是无偿的。由于存在诊断输出,命令将返回错误状态的可能性也很大,因此&&然后将无济于事。我建议删除它。
-
还要考虑输出可能非常大,并且对于cat,您将仅在最后看到grep,它将花费更多时间,并且如果没有足够的空间来写入临时文件则会失败。除非您需要随后随机访问输出,否则最好"在运行中"使用管道。