bash 仅通过过滤器输送 STDERR
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3618078/
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
Pipe only STDERR through a filter
提问by Martin DeMello
Is there any way, in bash, to pipe STDERR through a filter before unifying it with STDOUT? That is, I want
在 bash 中,有没有办法在将 STDERR 与 STDOUT 统一之前通过过滤器将其通过管道传输?也就是说,我想要
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
rather than
而不是
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘
采纳答案by Paul Rubel
Here's an example, modeled after how to swap file descriptors in bash. The output of a.out is the following, without the 'STDXXX: ' prefix.
这是一个示例,模仿如何在 bash 中交换文件描述符。a.out 的输出如下,没有“STDXXX:”前缀。
STDERR: stderr output
STDOUT: more regular
./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
more regular
stdErr output
Quoting from the above link:
引用上面的链接:
- First save stdout as &3 (&1 is duped into 3)
- Next send stdout to stderr (&2 is duped into 1)
- Send stderr to &3 (stdout) (&3 is duped into 2)
- close &3 (&- is duped into 3)
- 首先将标准输出保存为 &3(&1 被复制为 3)
- 接下来将标准输出发送到标准错误(&2 被欺骗为 1)
- 将 stderr 发送到 &3 (stdout)(&3 被欺骗成 2)
- 关闭 &3 (&- 被欺骗成 3)
回答by solidsnack
A naive use of process substitution seems to allow filtering of stderr
separately from stdout
:
进程替换的幼稚使用似乎允许stderr
从stdout
以下各项中单独过滤:
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
Note that stderr
comes out on stderr
and stdout
on stdout
, which we can see by wrapping the whole thing in another subshell and redirecting to files o
and e
需要注意的是stderr
出来上stderr
和stdout
上stdout
,我们可以在另一个子shell包裹了整个事情,并重定向到文件看到o
和e
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e
回答by Tom Hale
TL;DR:
特尔;博士:
$ cmd 2> >(stderr-filter >&2)
Example:
例子:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
This will work in both bash and zsh. Bash is pretty much ubiquitous these days, however, if you really do need a (really gnarly) solution for POSIX sh
, then see here.
这将适用于 bash 和 zsh。如今,Bash 几乎无处不在,但是,如果您确实需要一个(非常粗糙的)POSIX 解决方案sh
,请参阅此处。
Explanation
解释
By far, the easiest way to do this is to redirect STDERR via process substitution:
到目前为止,最简单的方法是通过进程替换重定向 STDERR :
Process substitution allows a process's input or output to be referred to using a filename. It takes the form of
>(list)
The process list is run asynchronously, and its input or output appears as a filename.
进程替换允许使用文件名引用进程的输入或输出。它采用以下形式
>(list)
进程列表异步运行,其输入或输出显示为文件名。
So what you get with process substituion is a filename.
所以你用进程替换得到的是一个文件名。
Just like you could do:
就像你可以这样做:
$ cmd 2> filename
you can do
你可以做
$ cmd 2> >(filter >&2)
The >&2
redirect's filter
's STDOUT back to the original STDERR.
该>&2
重定向的filter
的STDOUT回到原来的STDERR。
回答by Tom Hale
TL;DR: (bash and zsh)
TL;DR:(bash 和 zsh)
$ cmd 2> >(stderr-filter >&2)
Example:
例子:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Many answers on the StackExchange network have the form:
StackExchange 网络上的许多答案都具有以下形式:
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
This has a built-in assumption: that file descriptor 3 isn't being used for something else.
这有一个内置假设:文件描述符 3 没有用于其他用途。
Instead, use a named file descriptor, and {ba,z}sh
will allocate the next available file descriptor >= 10:
相反,使用命名的文件描述符,{ba,z}sh
并将分配下一个可用的文件描述符 >= 10:
cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
Note that named file descriptors aren't supported by POSIX sh
.
请注意, POSIX 不支持命名文件描述符sh
。
The other issue with the above is that the command cannot be piped to further commands without again swapping STDOUT and STDERR back to their original values.
上面的另一个问题是,如果不再次将 STDOUT 和 STDERR 交换回其原始值,则无法将命令通过管道传输到其他命令。
To allow onward piping in POSIX sh
, (and still assuming FD 3 is not it use) it gets complicated:
为了允许在 POSIX 中继续管道sh
,(并且仍然假设不使用 FD 3)它变得复杂:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
So, Given the assumption and gnarly syntax of this, you're likely to be better off using the simpler bash
/zsh
syntax shown in the TL;DR above, and explained here.
因此,鉴于此假设和粗糙的语法,您可能最好使用上面 TL;DR 中显示的更简单的bash
/zsh
语法,并在此处解释。
回答by Pecunifex
I find the use of bash process substitution easier to remember and use as it reflects the original intention almost verbatim. For example:
我发现使用 bash 进程替换更容易记住和使用,因为它几乎逐字反映了初衷。例如:
$ cat ./p
echo stdout
echo stderr >&2
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/'
sTdout
STderr
uses the first sed command as a filter on stderr only and the second sed command to modify the joined output.
使用第一个 sed 命令作为仅对 stderr 的过滤器,使用第二个 sed 命令来修改连接的输出。
Note that the white space after 2> is mandatory for the command to be parsed correctly.
请注意,2> 之后的空格是正确解析命令所必需的。
回答by signine
The last part of this pageof the Advanced Bash Scripting Guide is "redirecting only stderr to a pipe".
Advanced Bash Scripting Guide本页的最后一部分是“仅将 stderr 重定向到管道”。
# Redirecting only stderr to a pipe.
exec 3>&1 # Save current "value" of stdout. ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls'). # ^^^^ ^^^^ exec 3>&- # Now close it for the remainder of the script.
# Thanks, S.C.
# 仅将 stderr 重定向到管道。
exec 3>&1 # Save current "value" of stdout. ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls'). # ^^^^ ^^^^ exec 3>&- # Now close it for the remainder of the script.
#谢谢,SC
This may be what you want. If not, some other part of the ABSG should be able to help you, it is excellent.
这可能就是你想要的。如果没有,ABSG 的其他部分应该能够帮助你,它非常好。
回答by wilhelmtell
Take a look at named pipes:
看看命名管道:
$ mkfifo err
$ cmd1 2>err |cat - err |cmd2