在bash中,是否可以通过STDOUT统一将STDERR通过过滤器传递?那就是我想要
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
而不是
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘
Answers:
这是一个示例,以如何在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
从以上链接引用:
- 首先将标准输出另存为&3(&1分为3)
- 接下来将stdout发送到stderr(&2被复制为1)
- 将stderr发送到&3(stdout)(&3被分成2个)
- 关闭&3(&-分为3)
3>&2 2>&1 1>&3-
。
天真地使用流程替换似乎可以与以下内容stderr
分开过滤stdout
:
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
需要注意的是stderr
出来上stderr
和stdout
上stdout
,我们可以在另一个子shell包裹了整个事情,并重定向到文件看到o
和e
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e
$
用作命令提示符。然后,他们经常写信像贝壳的例子:$ cat /var/log/syslog | fgrep ...
。但是,由于导致该行不可复制粘贴$
。:;
看起来像是提示,但基本上是无操作的shell;因此您可以安全地选择并粘贴整行。
$ 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的(非常讨厌的)解决方案sh
,请参见此处。
到目前为止,最简单的方法是通过流程替换重定向STDERR :
进程替换允许使用文件名引用进程的输入或输出。它采取的形式
>(list)
进程列表是异步运行的,其输入或输出显示为文件名。
因此,使用过程替换得到的是文件名。
就像您可以做的一样:
$ cmd 2> filename
你可以做
$ cmd 2> >(filter >&2)
该>&2
重定向的filter
的STDOUT回到原来的STDERR。
exec 2> >(while .. read .. echo)
在执行作为systemd服务运行的脚本时,我为此而烦恼。journald捕获服务的fd2,并从'<N>'前缀推断日志级别:<2>
在输出行之前添加,并且您将ERROR级别分配给日记记录。但是有时systemd会在退出主进程最后一个最重要的消息之前迅速杀死整个进程组!
$ 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),它变得很复杂:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
因此,鉴于此假设和陈旧的语法,使用上面TL; DR中显示的更简单的bash
/zsh
语法并在此处进行说明,可能会更好。
Advanced Bash脚本指南的该页的最后一部分是“仅将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.
#谢谢,SC
这可能就是您想要的。如果没有,那么ABSG的其他部分应该可以为您提供帮助,这非常好。
看一下命名管道:
$ mkfifo err
$ cmd1 2>err |cat - err |cmd2
cat - err
破坏stdout和stderr的穿插?