Pipe only STDERR through a filter
在使用STDOUT统一它之前,有没有办法在bash中通过过滤器管道STDERR? 那就是我想要的
1 2 3  | STDOUT ────────────────┐ ├─────> terminal/file/whatever STDERR ── [ filter ] ──┘  | 
而不是
1 2 3  | STDOUT ────┐ ├────[ filter ]───> terminal/file/whatever STDERR ────┘  | 
这是一个例子,模仿如何在bash中交换文件描述符。 a.out的输出如下,没有'STDXXX:'前缀。
1 2 3 4 5 6  | STDERR: stderr output STDOUT: more regular ./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g' more regular stdErr output  | 
引用上面的链接:
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) 
过程替换的天真使用似乎允许从
1 2 3  | :; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) out e:err  | 
请注意
1  | ( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e  | 
TL; DR:
1  | $ cmd 2> >(stderr-filter >&2)  | 
例:
1 2 3  | % cat /non-existant 2> >(tr o X >&2) cat: /nXn-existant: NX such file Xr directXry %  | 
这将适用于bash和zsh。 Bash现在几乎无处不在,但是,如果你确实需要一个(非常粗糙)POSIX 
说明
到目前为止,最简单的方法是通过进程替换重定向STDERR:
Process substitution allows a process’s input or output to be referred to using a filename. It takes the form of
 1 >(list)The process list is run asynchronously, and its input or output appears as a filename.
所以你用过程替换得到的是一个文件名。
就像你能做的那样:
1  | $ cmd 2> filename  | 
你可以做
1  | $ cmd 2> >(filter >&2)  | 
我发现使用bash过程替换更容易记住和使用,因为它几乎逐字地反映了原始意图。例如:
1 2 3 4 5 6  | $ cat ./p echo stdout echo stderr >&2 $ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/' sTdout STderr  | 
使用第一个sed命令作为stderr的过滤器,第二个sed命令用于修改连接的输出。
请注意,2>之后的空格对于正确解析命令是必需的。
TL; DR:(bash和zsh)
1  | $ cmd 2> >(stderr-filter >&2)  | 
例:
1 2 3  | % cat /non-existant 2> >(tr o X >&2) cat: /nXn-existant: NX such file Xr directXry %  | 
StackExchange网络上的许多答案都有以下形式:
1  | cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'  | 
这有一个内置的假设:文件描述符3没有被用于其他东西。
相反,使用命名文件描述符,
1  | cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'  | 
请注意,POSIX 
上面的另一个问题是,如果不再将STDOUT和STDERR交换回其原始值,则无法将命令传送到其他命令。
为了允许在POSIX 
1  | (cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1  | 
所以,考虑到这个假设和粗略的语法,你可能会更好地使用TL中显示的更简单的
Advanced Bash Scripting Guide的这一页的最后一部分是"仅将stderr重定向到管道"。
# Redirecting only stderr to a pipe.
 1
2
3
4 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.
这可能就是你想要的。如果没有,ABSG的其他部分应该能够帮助你,这是非常好的。
看一下命名管道:
1 2  | $ mkfifo err $ cmd1 2>err |cat - err |cmd2  |