使用进程替换-仅将stderr发送到文件。

5

由于某种原因,在以下bash脚本中,似乎stderr被发送到了stdout:

exec > >( while read line; do echo " stdout: $line"; done )
exec 2> >( while read line; do echo " stderr: $line"; done )

echo "rolo"
echo "cholo" >&2

如果你运行这段代码,输出结果如下:

标准输出:rolo
标准错误:cholo

有人知道为什么会这样吗?据我所知,发生的情况是stderr被发送到了stdout,这就是为什么第一行捕获了第二行的输出。


2
你在制作MCVE方面做得很好。 - Jonathan Leffler
是的,人们会喜欢这个哈哈,我今天发现了这个技巧。 - user5047085
1个回答

5

是的-你的标准错误已经被发送到标准输出。这是你要求发生的事情。

你的exec 2> >(…)脚本正在回显到stdout,所以exec > >(…)脚本也可以看到它-这就是为什么你在cholo输出行上有stdoutstderr标签的原因。

修改你的脚本(bash17.sh)为:

exec  > >( while read line; do echo " stdout: $line"; done     )
exec 2> >( while read line; do echo " stderr: $line"; done >&2 )

echo "rolo"
echo "cholo" >&2

这样标准错误将会输出到标准错误流,并且您会看到:
$ bash bash17.sh
 stdout: rolo
 stderr: cholo
$ bash bash17.sh > /dev/null
 stderr: cholo
$ bash bash17.sh 2> /dev/null
 stdout: rolo
$

显然,要将标准错误信息输出到文件中,你需要在脚本的exec 2> >(…)部分内使用一种替代的重定向方式。


我想我不明白为什么 exec 2> >(…) 会回显到标准输出?为什么会这样? - user5047085
反转exec操作的顺序应该可以解决问题。2>进程将其标准输出发送到原始位置;然后,>进程仅拦截其他标准输出。当然,如果没有与2>相关联的>&2,输出将会被发送到标准输出而不是标准错误,但它不会被其他子进程过滤/拦截/处理。 - Jonathan Leffler
2> 符号中的子进程具有写入其标准输出的 echo 命令。由于您没有更改子进程的输出,因此它与主 shell 的标准输出到达相同的位置。否则,这些 echos 还会回显到哪里呢?它们的输入来自原始标准错误,但这不是它们输出去向的因素。 - Jonathan Leffler
哦,嗯,回显将会输出到标准输出流,现在这就有意义了。 - user5047085
1
>&2放在循环外部意味着重定向只会执行一次,而不是每行都执行一次。在示例脚本中,只有一行需要读取,所以这没有什么影响。在实际应用中,这可能会产生微小的差异,但你很难测量出来。 - Jonathan Leffler
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接