我有一个程序,将信息写入标准输出和标准错误,我需要用grep处理标准错误,把标准错误放在一边。
使用临时文件,可以分两步完成:
command > /dev/null 2> temp.file
grep 'something' temp.file
但是,在没有临时文件的情况下,如何使用一个命令和管道实现这一点呢?
我有一个程序,将信息写入标准输出和标准错误,我需要用grep处理标准错误,把标准错误放在一边。
使用临时文件,可以分两步完成:
command > /dev/null 2> temp.file
grep 'something' temp.file
但是,在没有临时文件的情况下,如何使用一个命令和管道实现这一点呢?
当前回答
对于那些想要将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
其他回答
您可以使用rc外壳。
首先安装包(小于1mb)。
这是一个如何在rc中丢弃标准输出和管道标准错误到grep的例子:
find /proc/ >[1] /dev/null |[2] grep task
你可以在不离开Bash的情况下完成:
rc -c 'find /proc/ >[1] /dev/null |[2] grep task'
您可能已经注意到,可以通过在管道后面使用括号来指定想要管道的文件描述符。
标准文件描述符的编号如下:
0:标准输入 1:标准输出 2:标准错误
对于那些想要将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
如果你正在使用Bash,那么使用:
command >/dev/null |& grep "something"
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
这将重定向command1 stderr到command2 stdin,同时保留command1 stdout原样。
exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-
摘自LDP
如果你思考一下“重定向”和“管道”到底发生了什么,就会更容易形象化。bash中的重定向和管道只做一件事:修改进程文件描述符0、1和2所指向的地方(参见/proc/[pid]/fd/*)。
当命令行上出现管道或“|”操作符时,首先发生的事情是bash创建一个fifo,并将左侧命令的FD 1指向这个fifo,并将右侧命令的FD 0指向相同的fifo。
接下来,从左到右计算每一侧的重定向操作符,每当出现描述符复制时,就使用当前设置。这很重要,因为管道是先设置的,FD1(左侧)和FD0(右侧)已经与正常情况不同,任何复制都将反映这一事实。
因此,当你输入如下内容时:
command 2>&1 >/dev/null | grep 'something'
以下是发生的事情,按顺序排列:
创建管道(fifo)。“命令FD1”指向这个管道。"grep FD0"也指向这个管道 “命令FD2”指向“命令FD1”当前指向的位置(管道) “command FD1”指向/dev/null
因此,“命令”写入其FD 2 (stderr)的所有输出都会进入管道,并由另一端的“grep”读取。“命令”写入其FD 1 (stdout)的所有输出都会进入/dev/null
如果相反,运行以下命令:
command >/dev/null 2>&1 | grep 'something'
事情是这样的:
一个管道被创建,“命令FD 1”和“grep FD 0”指向它 “命令FD 1”指向/dev/null “命令FD 2”指向FD 1当前指向的位置(/dev/null)
因此,所有来自"command"的stdout和stderr都将转到/dev/null.没有任何东西进入管道,因此“grep”将关闭,而不会在屏幕上显示任何东西。
还要注意,重定向(文件描述符)可以是只读(<)、只写(>)或读写(<>)。
最后一点。一个程序写东西到FD1还是FD2,完全取决于程序员。良好的编程实践规定,错误消息应该发送到FD 2,正常输出应该发送到FD 1,但您经常会发现混淆了这两者或以其他方式忽略约定的草率编程。