代码之家  ›  专栏  ›  技术社区  ›  user80168

如何处理stderr,而不是stdout?

  •  830
  • user80168  · 技术社区  · 14 年前

    我有一个程序可以将信息写入 stdout stderr 我需要 grep 通过即将发生的事情 标准错误 ,而忽略 标准输出 .

    我当然可以分两步完成:

    command > /dev/null 2> temp.file
    grep 'something' temp.file
    

    但我更愿意在没有临时文件的情况下完成这项工作。有什么巧妙的管道技巧吗?

    11 回复  |  直到 5 年前
        1
  •  992
  •   Jonathan Leffler    6 年前

    首先将stderr重定向到管道的stdout_ /dev/null (不改变stderr的去向):

    command 2>&1 >/dev/null | grep 'something'
    

    有关各种I/O重定向的详细信息,请参阅 Redirections 在bash参考手册中。

    注意,I/O重定向的顺序是从左到右解释的,但是管道是在解释I/O重定向之前设置的。文件描述符(如1和2)是对打开文件描述的引用。手术 2>&1 使文件描述符2(aka stderr)引用与文件描述符1(aka stdout当前引用)相同的打开文件描述(请参见 dup2() open() )手术 >/dev/null 然后更改文件描述符1,使其引用 /DEV/NULL 但这并不能改变文件描述符2引用文件描述符1最初指向的“打开的文件”描述的事实,即管道。

        2
  •  323
  •   kvantour    6 年前

    或者将stderr和stdout的输出交换为过度使用:

    command 3>&1 1>&2 2>&3
    

    这将创建一个新的文件描述符(3)并将其分配到与1(stdout)相同的位置,然后将fd 1(stdout)分配到与fd 2(stderr)相同的位置,最后将fd 2(stderr)分配到与fd 3(stdout)相同的位置。stderr现在可用作stdout,旧stdout保留在stderr中。这可能有点过分,但希望能提供更多关于bash文件描述符的详细信息(每个进程有9个可用的描述符)。

        3
  •  189
  •   Jonathan Leffler    8 年前

    在bash中,还可以使用 process substitution :

    command > >(stdlog pipe)  2> >(stderr pipe)
    

    对于手头的案件:

    command 2> >(grep 'something') >/dev/null
    
        4
  •  160
  •   Pinko    6 年前

    结合这些最佳答案,如果您这样做:

    command 2> >(grep -v something 1>&2)

    …然后所有stdout都保存为stdout 所有stderr都保留为stderr,但在stderr中不会看到包含字符串“something”的任何行。

    这有一个独特的优点,即不会反转或丢弃stdout和stderr,也不会将它们弄脏在一起,也不会使用任何临时文件。

        5
  •  91
  •   Michael Martinez    11 年前

    如果您考虑“重定向”和“管道”的实际情况,那么可视化事情就容易得多。bash中的重定向和管道只做一件事:修改进程文件描述符0、1和2指向的位置(请参见/proc/[pid]/fd/*)。

    当一个 或者“”操作符出现在命令行上,首先发生的事情是bash创建一个fifo并将左侧命令的fd 1指向这个fifo,并将右侧命令的fd 0指向同一个fifo。

    接下来,对每一方的重定向操作符进行评估 从左到右 和当前设置将在描述符出现重复时使用。这一点很重要,因为由于首先设置了管道,因此FD1(左侧)和FD0(右侧)已经与正常情况不同,任何重复都会反映出这一事实。

    因此,当您键入如下内容时:

    command 2>&1 >/dev/null | grep 'something'
    

    以下是发生的事情,顺序如下:

    1. 将创建管道(FIFO)。命令FD1“指向此管道。GREP FD0“也指向此管道
    2. “command fd2”指向“command fd1”当前指向的位置(管道)
    3. “command fd1”指向/dev/null

    因此,“command”写入其fd 2(stderr)的所有输出都会进入管道,并由另一侧的“grep”读取。“command”写入其fd 1(stdout)的所有输出都会进入/dev/null。

    如果改为运行以下命令:

    command >/dev/null 2>&1 | grep 'something'
    

    以下是发生的事情:

    1. 创建一个管道,并将“command fd 1”和“grep fd 0”指向它
    2. “command fd 1”指向/dev/null
    3. “command fd 2”指向fd 1当前指向的位置(/dev/null)

    所以,来自“command”的所有stdout和stderr都将转到/dev/null。管道中没有任何内容,因此“grep”将关闭,而不在屏幕上显示任何内容。

    还要注意,重定向(文件描述符)可以是只读的(<)、只读的(>)或读写的(<>)。

    最后一个音符。程序是否向FD1或FD2写入某些内容完全取决于程序员。良好的编程实践要求错误消息应该转到fd 2,正常输出到fd 1,但是您经常会发现混合了这两者的编程很草率,或者忽略了约定。

        6
  •  29
  •   Ken Sharp    10 年前

    你在用bash吗?如果是这样:

    command >/dev/null |& grep "something"
    

    http://www.gnu.org/software/bash/manual/bashref.html#Pipelines

        7
  •  9
  •   JBD    11 年前

    对于那些希望将stdout和stderr永久重定向到文件的用户,请在stderr上grep,但保留stdout以将消息写入tty:

    # save tty-stdout to fd 3
    exec 3>&1
    # switch stdout and stderr, grep (-v) stderr for nasty messages and append to files
    exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out
    # goes to the std.out
    echo "my first message" >&1
    # goes to the std.err
    echo "a error message" >&2
    # goes nowhere
    echo "this nasty_msg won't appear anywhere" >&2
    # goes to the tty
    echo "a message on the terminal" >&3
    
        8
  •  5
  •   theDolphin    10 年前

    这将把command1 stderr重定向到command2 stdin,同时保持command1 stdout不变。

    exec 3>&1
    command1 2>&1 >&3 3>&- | command2 3>&-
    exec 3>&-
    

    取自 LDP

        9
  •  1
  •   Tripp Kinetics    6 年前

    我刚想出一个解决方案 stdout 一个命令和 stderr 到另一个,使用命名管道。

    给你。

    mkfifo stdout-target
    mkfifo stderr-target
    cat < stdout-target | command-for-stdout &
    cat < stderr-target | command-for-stderr &
    main-command 1>stdout-target 2>stderr-target
    

    以后移除命名管道可能是个好主意。

        10
  •  -1
  •   djfm    5 年前

    我喜欢做这样的事情

    作曲家测试/tmp/bob&vim/tmp/bob&rm/tmp/bob

        11
  •  -3
  •   lasteye    6 年前

    我试着跟随,发现它也起作用,

    command > /dev/null 2>&1 | grep 'something'