仅通过过滤器管道STDERR

时间:2010-09-01 12:44:58

标签: linux bash redirect

在使用STDOUT统一它之前,是否有任何方法在bash中通过过滤器管道STDERR?也就是说,我想要

STDOUT ────────────────┐
                       ├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘

而不是

STDOUT ────┐
           ├────[ filter ]───> terminal/file/whatever
STDERR ────┘

7 个答案:

答案 0 :(得分:56)

这是一个以how to swap file descriptors in 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

从以上链接引用:

  
      
  1. 首先将stdout保存为& 3(& 1加入3)
  2.   
  3. 接下来将stdout发送到stderr(& 2被骗到1)
  4.   
  5. 将stderr发送到& 3(stdout)(& 3被骗到2)
  6.   
  7. close& 3(& - 被骗入3)
  8.   

答案 1 :(得分:20)

过程替换的天真使用似乎允许stderrstdout分开过滤:

:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err

请注意stderr stderrstdout stdout上出现o,我们可以通过将整个内容包装到另一个子shell并重定向到文件{{1}来看到}和e

( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e

答案 2 :(得分:8)

我发现bash过程替换的使用更容易记住和使用,因为它几乎逐字地反映了原始意图。例如:

$ cat ./p
echo stdout
echo stderr >&2
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/'
sTdout
STderr

仅使用第一个sed命令作为stderr的过滤器,使用第二个sed命令修改连接的输出。

注意2>之后的空格>必须正确解析命令。

答案 3 :(得分:8)

TL; DR:

$ cmd 2> >(stderr-filter >&2)

示例:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

这将同时在bash和zsh中工作。如今,Bash几乎无处不在,但是,如果您确实确实需要针对POSIX shsp_BlitzCache的(非常讨厌)解决方案。


说明

到目前为止,最简单的方法是通过see here重定向STDERR:

  

进程替换允许使用文件名引用进程的输入或输出。它采用

的形式
>(list)
     

进程列表是异步运行的,其输入或输出显示为文件名。

所以用流程替换得到的是文件名。

就像您可以做的一样:

$ cmd 2> filename

你可以做

$ cmd 2> >(filter >&2)

>&2重定向的filter的STDOUT返回原始STDERR。

答案 4 :(得分:5)

Advanced Bash脚本编写指南的this page的最后一部分是“仅将stderr重定向到管道”。

  

#仅将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.
     

#Thanks,S.C。

这可能就是你想要的。如果没有,ABSG的其他部分应该能够帮助你,这非常好。

答案 5 :(得分:5)

TL; DR:(bash和zsh)

$ cmd 2> >(stderr-filter >&2)

示例:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

StackExchange网络上的许多答案都采用以下形式:

cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'

这是一个内置的假设:文件描述符3并未用于其他用途。

相反,请使用命名文件描述符,{ba,z}sh将分配下一个可用的文件描述符> = 10:

cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'

请注意,POSIX sh不支持命名文件描述符。

上述内容的另一个问题是,如果不再次将STDOUT和STDERR交换回其原始值,则无法将该命令传递给其他命令。

要允许在POSIX sh中继续管道传输(并且仍然假设未使用FD 3),请使用gets complicated

(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1

因此,鉴于此假设和陈旧的语法,使用上面的TL; DR中显示的简单bash / zsh语法并解释{{3 }}。

答案 6 :(得分:3)

看一下命名管道:

$ mkfifo err
$ cmd1 2>err |cat - err |cmd2