【问题标题】:How can I redirect STDERR to STDOUT, but ignore the original STDOUT? [duplicate]如何将 STDERR 重定向到 STDOUT,但忽略原始的 STDOUT? [复制]
【发布时间】:2010-10-07 16:14:27
【问题描述】:

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

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

【问题讨论】:

    标签: bash redirect stdout


    【解决方案1】:

    什么不起作用:

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

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

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

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

    什么有效:

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

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

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


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

    cmd 2>&1 >&- | grep pattern
    

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

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

    【讨论】:

    • 干得好!毫无疑问,我会一遍又一遍地回到这个页面,以便在我需要的时候进行查找。
    【解决方案2】:

    先关闭STDOUT:

    1>&-, >&-
    

    here

    【讨论】:

    • 嗯,你确定这会做 OP 想要的吗?对我来说似乎不是。如果您先关闭 stdout,则无法将 stderr 重定向到它。
    • 好的,基于此,我发现这行得通:2>&1>&-。也许你可以更新答案,因为它目前是这样写的,可以试试这个:>&- 2>&1,这不起作用。
    • 是的,这样(在重定向后关闭它)它可以工作,并且在支持的地方有时比使用 /dev/null 更好,因为你节省了写入 - 我会更新我的答案来提及这一点。请注意,这是一些 shell(包括 bash)支持的扩展,但在 sh 中显然不是标准的。
    • 关闭标准输出,而不是发送到 /dev/null,只有在写入标准输出的命令忽略了写入错误时才有效——事实上,这是对 C 编程的一个悲伤评论,事实上,大多数时候,程序将忽略这些错误。
    • @查理·马丁。对,它被标记为 bash,答案可能很好。我对 bash 的扩展了解不多,所以我实际上在这里学到了一些新东西 :-)
    【解决方案3】:

    我会尝试一些简单的方法,例如:

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

    【讨论】:

    • 选择的答案表明这是不必要的。您在第二部分中使用 cat 是无偿的。由于有诊断输出,该命令也很有可能返回错误状态,因此 && 将无济于事。我建议删除它。
    • 还要考虑到输出可能会很大,用cat只会看到最后的grep,会比较费时间,如果没有足够的空间写临时文件会失败.除非您以后需要随机访问输出,否则最好“即时”使用管道。
    猜你喜欢
    • 1970-01-01
    • 2014-07-22
    • 2022-01-18
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 2011-11-23
    • 2011-05-23
    • 2011-07-22
    相关资源
    最近更新 更多