933 bash grep stdout pipe stderr
我有一个程序可以将信息写入stdout和stderr,并且我需要grep通过什么来到stderr,而忽略了stdout.
我当然可以分2步完成:
command > /dev/null 2> temp.file
grep 'something' temp.file
Run Code Online (Sandbox Code Playgroud)
但我宁愿能够在没有临时文件的情况下做到这一点.有没有任何智能管道技巧?
Jon*_*ler 1114
首先将stderr重定向到stdout - 管道; 然后将stdout重定向到/dev/null(不改变stderr的去向):
command 2>&1 >/dev/null | grep 'something'
Run Code Online (Sandbox Code Playgroud)
有关各种I/O重定向的详细信息,请参阅Bash参考手册中有关重定向的章节.
请注意,I/O重定向的顺序是从左到右解释的,但在解释I/O重定向之前会设置管道.文件描述符(如1和2)是对打开文件描述的引用.该操作2>&1使得文件描述符2也称为stderr引用与文件描述符1相同的打开文件描述,也就是stdout当前所指的(参见dup2()和open()).然后,操作>/dev/null改变文件描述符1,使其引用打开的文件描述/dev/null,但这不会改变文件描述符2引用文件描述符1最初指向的打开文件描述的事实 - 即管道.
小智 346
或者在使用时交换stderr和stdout的输出: -
command 3>&1 1>&2 2>&3
Run Code Online (Sandbox Code Playgroud)
这将创建一个新的文件描述符(3)并将其分配到与1(stdout)相同的位置,然后将fd 1(stdout)分配给与fd 2(stderr)相同的位置,最后将fd 2(stderr)分配给相同的位置放置为fd 3(标准输出).Stderr现在可以作为stdout使用,旧stdout保存在stderr中.这可能有点过分,但希望提供有关bash文件描述符的更多详细信息(每个进程有9个可用).
小智 204
在Bash中,您还可以使用进程替换重定向到子shell :
command > >(stdlog pipe) 2> >(stderr pipe)
Run Code Online (Sandbox Code Playgroud)
对于手头的情况:
command 2> >(grep 'something') >/dev/null
Run Code Online (Sandbox Code Playgroud)
Pin*_*nko 184
结合这些答案中的最佳答案,如果您这样做:
command 2> >(grep -v something 1>&2)
...然后所有stdout都保存为stdout,并且所有stderr都保存为stderr,但是你不会在stderr中看到包含字符串"something"的任何行.
这具有独特的优点,即不反转或丢弃stdout和stderr,也不会将它们混合在一起,也不使用任何临时文件.
Mic*_*nez 96
如果你想一想"重定向"和"管道"的真实情况,那么可视化的东西要容易得多.bash中的重定向和管道做一件事:修改进程文件描述符0,1和2指向的位置(参见/ proc/[pid]/fd/*).
当管道或"|" 运算符出现在命令行中,首先要发生的是bash创建一个fifo并将左侧命令的FD 1指向此fifo,并将右侧命令的FD 0指向同一个fifo.
接下来,从左到右评估每一侧的重定向运算符,并且每当重复描述符时使用当前设置.这很重要,因为由于管道是先设置的,所以FD1(左侧)和FD0(右侧)已经从它们通常的状态改变,而这些的重复将反映这一事实.
因此,当您键入以下内容时:
command 2>&1 >/dev/null | grep 'something'
Run Code Online (Sandbox Code Playgroud)
以下是按顺序发生的事情:
因此,"命令"写入其FD 2(stderr)的所有输出都进入管道,并由另一侧的"grep"读取."命令"写入其FD 1(stdout)的所有输出都会进入/ dev/null.
相反,如果您运行以下内容:
command >/dev/null 2>&1 | grep 'something'
Run Code Online (Sandbox Code Playgroud)
这是发生的事情:
所以,"command"中的所有stdout和stderr都转到/ dev/null.没有任何东西进入管道,因此"grep"将关闭而不在屏幕上显示任何内容.
另请注意,重定向(文件描述符)可以是只读(<),只写(>)或读写(<>).
最后一点.程序是否将某些内容写入FD1或FD2,完全取决于程序员.良好的编程习惯要求错误消息应该转到FD 2并且正常输出转换为FD 1,但是您经常会发现混合两者的草率编程或者忽略惯例.
Ken*_*arp 35
你在用bash吗?如果是这样:
command >/dev/null |& grep "something"
Run Code Online (Sandbox Code Playgroud)
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
JBD*_*JBD 10
对于那些想要将stdout和stderr永久重定向到文件的人,grep on stderr,但是让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
Run Code Online (Sandbox Code Playgroud)
这会将command1 stderr重定向到command2 stdin,同时保留command1 stdout.
exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-
Run Code Online (Sandbox Code Playgroud)
取自自民党