bash 我如何通过管道 stderr 而不是 stdout?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2342826/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I pipe stderr, and not stdout?
提问by Jonathan Leffler
I have a program that writes information to stdout
and stderr
, and I need to grep
through what's coming to stderr, while disregarding stdout.
我有一个将信息写入stdout
and的程序,stderr
我需要grep
通过stderr 的内容,而忽略stdout。
I can of course do it in 2 steps:
我当然可以分两步完成:
command > /dev/null 2> temp.file
grep 'something' temp.file
but I would prefer to be able to do this without temp files. Are there any smart piping tricks?
但我希望能够在没有临时文件的情况下做到这一点。有什么聪明的管道技巧吗?
回答by Jonathan Leffler
First redirect stderr to stdout — the pipe; then redirect stdout to /dev/null
(without changing where stderr is going):
首先将 stderr 重定向到 stdout — 管道;然后将 stdout 重定向到/dev/null
(不改变 stderr 的去向):
command 2>&1 >/dev/null | grep 'something'
For the details of I/O redirection in all its variety, see the chapter on Redirectionsin the Bash reference manual.
有关各种 I/O 重定向的详细信息,请参阅Bash 参考手册中有关重定向的章节。
Note that the sequence of I/O redirections is interpreted left-to-right, but pipes are set up before the I/O redirections are interpreted. File descriptors such as 1 and 2 are references to open file descriptions. The operation 2>&1
makes file descriptor 2 aka stderr refer to the same open file description as file descriptor 1 aka stdout is currently referring to (see dup2()
and open()
). The operation >/dev/null
then changes file descriptor 1 so that it refers to an open file description for /dev/null
, but that doesn't change the fact that file descriptor 2 refers to the open file description which file descriptor 1 was originally pointing to — namely, the pipe.
请注意,I/O 重定向的顺序是从左到右解释的,但管道是在解释 I/O 重定向之前设置的。诸如 1 和 2 之类的文件描述符是对打开文件描述的引用。该操作2>&1
使文件描述符 2 aka stderr 引用与文件描述符 1 aka stdout 当前引用的相同的打开文件描述(参见dup2()
和open()
)。>/dev/null
然后该操作更改文件描述符 1,使其引用 的打开文件描述/dev/null
,但这并没有改变文件描述符 2 引用文件描述符 1 最初指向的打开文件描述的事实——即管道。
回答by Kramish
Or to swap the output from standard error and standard output over, use:
或者要交换标准错误和标准输出的输出,请使用:
command 3>&1 1>&2 2>&3
This creates a new file descriptor (3) and assigns it to the same place as 1 (standard output), then assigns fd 1 (standard output) to the same place as fd 2 (standard error) and finally assigns fd 2 (standard error) to the same place as fd 3 (standard output).
这将创建一个新的文件描述符 (3) 并将其分配到与 1(标准输出)相同的位置,然后将 fd 1(标准输出)分配到与 fd 2(标准错误)相同的位置,最后将 fd 2(标准错误)分配到相同的位置) 到与 fd 3(标准输出)相同的位置。
Standard error is now available as standard output and the old standard output is preserved in standard error. This may be overkill, but it hopefully gives more details on Bash file descriptors (there are nine available to each process).
标准错误现在可用作标准输出,旧标准输出保留在标准错误中。这可能有点矫枉过正,但它希望提供有关 Bash 文件描述符的更多详细信息(每个进程有 9 个可用)。
回答by Rich Johnson
In Bash, you can also redirect to a subshell using process substitution:
在 Bash 中,您还可以使用进程替换重定向到子 shell :
command > >(stdlog pipe) 2> >(stderr pipe)
For the case at hand:
对于手头的案例:
command 2> >(grep 'something') >/dev/null
回答by Pinko
Combining the best of these answers, if you do:
结合这些答案中最好的,如果你这样做:
command 2> >(grep -v something 1>&2)
command 2> >(grep -v something 1>&2)
...then all stdout is preserved as stdout andall stderr is preserved as stderr, but you won't see any lines in stderr containing the string "something".
...然后所有标准输出都保留为标准输出,所有标准错误都保留为标准错误,但您不会在标准错误中看到任何包含字符串“something”的行。
This has the unique advantage of not reversing or discarding stdout and stderr, nor smushing them together, nor using any temporary files.
这具有独特的优势,即不会反转或丢弃 stdout 和 stderr,也不会将它们混在一起,也不会使用任何临时文件。
回答by Michael Martinez
It's much easier to visualize things if you think about what's really going on with "redirects" and "pipes." Redirects and pipes in bash do one thing: modify where the process file descriptors 0, 1, and 2 point to (see /proc/[pid]/fd/*).
如果您考虑一下“重定向”和“管道”的实际情况,将事情形象化要容易得多。bash 中的重定向和管道只做一件事:修改进程文件描述符 0、1 和 2 指向的位置(参见 /proc/[pid]/fd/*)。
When a pipeor "|" operator is present on the command line, the first thing to happen is that bash creates a fifo and points the left side command's FD 1 to this fifo, and points the right side command's FD 0 to the same fifo.
当管道或“|” 操作符出现在命令行上,首先发生的是 bash 创建一个 fifo 并将左侧命令的 FD 1 指向这个 fifo,并将右侧命令的 FD 0 指向同一个 fifo。
Next, the redirect operators for each side are evaluated from left to right, and the current settings are used whenever duplication of the descriptor occurs. This is important because since the pipe was set up first, the FD1 (left side) and FD0 (right side) are already changed from what they might normally have been, and any duplication of these will reflect that fact.
接下来,从左到右评估每一侧的重定向运算符,并且每当出现描述符重复时使用当前设置。这很重要,因为由于管道是首先设置的,FD1(左侧)和 FD0(右侧)已经从它们通常的状态发生了变化,这些的任何重复都将反映这一事实。
Therefore, when you type something like the following:
因此,当您键入以下内容时:
command 2>&1 >/dev/null | grep 'something'
Here is what happens, in order:
这是发生的事情,按顺序:
- a pipe (fifo) is created. "command FD1" is pointed to this pipe. "grep FD0" also is pointed to this pipe
- "command FD2" is pointed to where "command FD1" currently points (the pipe)
- "command FD1" is pointed to /dev/null
- 一个管道(fifo)被创建。“命令 FD1”指向这个管道。“grep FD0”也指向这个管道
- “command FD2”指向“command FD1”当前指向的位置(管道)
- “命令 FD1”指向 /dev/null
So, all output that "command" writes to its FD 2 (stderr) makes its way to the pipe and is read by "grep" on the other side. All output that "command" writes to its FD 1 (stdout) makes its way to /dev/null.
因此,“command”写入其 FD 2 (stderr) 的所有输出都进入管道,并由另一侧的“grep”读取。“命令”写入其 FD 1 (stdout) 的所有输出都会进入 /dev/null。
If instead, you run the following:
如果相反,您运行以下命令:
command >/dev/null 2>&1 | grep 'something'
Here's what happens:
这是发生的事情:
- a pipe is created and "command FD 1" and "grep FD 0" are pointed to it
- "command FD 1" is pointed to /dev/null
- "command FD 2" is pointed to where FD 1 currently points (/dev/null)
- 一个管道被创建并且“command FD 1”和“grep FD 0”指向它
- “命令 FD 1”指向 /dev/null
- “命令 FD 2”指向 FD 1 当前指向的位置 (/dev/null)
So, all stdout and stderr from "command" go to /dev/null. Nothing goes to the pipe, and thus "grep" will close out without displaying anything on the screen.
因此,所有来自“command”的 stdout 和 stderr 都转到 /dev/null。管道没有任何内容,因此“grep”将关闭而不在屏幕上显示任何内容。
Also note that redirects (file descriptors) can be read-only (<), write-only (>), or read-write (<>).
另请注意,重定向(文件描述符)可以是只读 (<)、只写 (>) 或读写 (<>)。
A final note. Whether a program writes something to FD1 or FD2, is entirely up to the programmer. Good programming practice dictates that error messages should go to FD 2 and normal output to FD 1, but you will often find sloppy programming that mixes the two or otherwise ignores the convention.
最后一点。程序是否向 FD1 或 FD2 写入内容完全取决于程序员。良好的编程习惯要求错误消息应该发送到 FD 2,正常输出应该发送到 FD 1,但是您经常会发现草率的编程将两者混合或以其他方式忽略约定。
回答by Ken Sharp
If you are using Bash, then use:
如果您使用的是 Bash,请使用:
command >/dev/null |& grep "something"
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
回答by JBD
For those who want to redirect stdout and stderr permanently to files, grep on stderr, but keep the stdout to write messages to a tty:
对于那些想要将 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
回答by theDolphin
回答by Tripp Kinetics
I just came up with a solution for sending stdout
to one command and stderr
to another, using named pipes.
我刚刚想出了一种使用命名管道发送stdout
到一个命令和stderr
另一个命令的解决方案。
Here goes.
开始。
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
It's probably a good idea to remove the named pipes afterward.
之后删除命名管道可能是个好主意。
回答by Rolf
You can use the rc shell.
您可以使用rc shell。
First install the package (it's less than 1 MB).
首先安装软件包(小于 1 MB)。
This an example of how you would discard standard output and pipe standard error to grepin rc
:
这是您如何丢弃标准输出并将标准错误通过管道传递给grepin的示例rc
:
find /proc/ >[1] /dev/null |[2] grep task
You can do it without leaving Bash:
你可以在不离开 Bash 的情况下做到这一点:
rc -c 'find /proc/ >[1] /dev/null |[2] grep task'
As you may have noticed, you can specify which file descriptor you want piped by using brackets after the pipe.
您可能已经注意到,您可以通过在管道后使用方括号来指定要通过管道传输的文件描述符。
Standard file descriptors are numerated as such:
标准文件描述符的编号如下:
- 0 : Standard input
- 1 : Standard output
- 2 : Standard error
- 0 : 标准输入
- 1:标准输出
- 2:标准误差