pipe道标准输出和标准错误到两个不同的进程在shell脚本?
我有一个pipline正在做
command1 | command2
所以,命令1的标准输出到命令2,而命令1的标准input到terminal(或shell的标准输出)。
如何将标准输出stderr的command3
到第三个进程( command3
),而标准输出仍然是命令2?
使用另一个文件描述符
{ command1 2>&3 | command2; } 3>&1 1>&2 | command3
您最多可以使用7个其他文件描述符:从3到9。
如果你想更多的解释,请问,我可以解释;-)
testing
{ { echo a; echo >&2 b; } 2>&3 | sed >&2 's/$/1/'; } 3>&1 1>&2 | sed 's/$/2/'
输出:
b2 a1
例
生成两个日志文件:
只有stderr
2. stderr
和stdout
{ { { command 2>&1 1>&3; } | tee err-only.log; } 3>&1; } > err-and-stdout.log
如果command
是echo "stdout"; echo "stderr" >&2
echo "stdout"; echo "stderr" >&2
然后我们可以像这样testing它:
$ { { { echo out>&3;echo err>&1;}| tee err-only.log;} 3>&1;} > err-and-stdout.log $ head err-only.log err-and-stdout.log ==> err-only.log <== err ==> err-and-stdout.log <== out err
接受的答案导致stdout
和stderr
。 这里有一个方法,保留它们(因为谷歌search引起了这个post):
{ command 2>&1 1>&3 3>&- | stderr_command; } 3>&1 1>&2 | stdout_command
注意:
-
3>&-
是防止fd 3被command
inheritance所必需的。 (因为这可能会导致意外的结果取决于内部的command
。)
部分解释:
-
外部第一:
-
3>&1
– fd 3 for{ ... }
被设置为fd 1 (即stdout
) -
1>&2
– fd 1 for{ ... }
被设置为fd 2的值 (即stderr
) -
| stdout_command
| stdout_command
– fd 1 (stdout
)通过stdout_command
传送
-
-
内部部分从外部inheritance文件描述符:
-
2>&1
– fd 2 forcommand
被设置为fd 1的值 (即每个外部的stderr
) -
1>&3
– fd 1 forcommand
设置为fd 3 (即每个外部的stdout
) -
3>&-
– fd 3 forcommand
设置为空(即closures ) -
| stderr_command
| stderr_command
– fd 1 (stderr
)通过stderr_command
进行stderr_command
-
例:
foo() { echo a echo b >&2 echo c echo d >&2 } { foo 2>&1 1>&3 3>&- | sed -u 's/^/err: /'; } 3>&1 1>&2 | sed -u 's/^/out: /'
输出:
out: a err: b err: d out: c
( a -> c
和b -> d
顺序总是不确定的,因为stderr_command
和stdout_command
之间没有任何同步。)
只需将stderrredirect到标准输出
{ command1 | command2; } 2>&1 | command3
警告: commnd3
也会读取command2
stdout(如果有的话)。
为了避免这种情况,可以丢弃commnd2
stdout:
{ command1 | command2 >/dev/null; } 2>&1 | command3
但是,要保持command2
标准输出(例如在terminal中),
那么请参考我的其他答案比较复杂。
testing
{ { echo -e "a\nb\nc" >&2; echo "----"; } | sed 's/$/1/'; } 2>&1 | sed 's/$/2/'
输出:
a2 b2 c2 ----12
用fifo可以很容易地完成同样的效果。 我不知道这样做的直接pipe道语法(虽然它会很漂亮,看到一个)。 这就是你如何使用fifo来完成的。
首先,打印到stdout
和stderr
, outerr.sh
:
#!/bin/bash echo "This goes to stdout" echo "This goes to stderr" >&2
然后我们可以做这样的事情:
$ mkfifo err $ wc -c err & [1] 2546 $ ./outerr.sh 2>err | wc -c 20 20 err [1]+ Done wc -c err
这样,您首先设置stderr
输出的侦听器,并使用语法2>err
阻塞,直到它具有一个写入器(发生在下一个命令中)。 你可以看到每个wc -c
都有20个字符的input。
不要忘记在完成后清理FIFO,如果你不想它挂在(即rm
)。 如果另一个命令需要inputstdin
而不是arg文件,则可以使用inputredirect,如wc -c < err
。