Bash将stdout发送到一个进程,将stderr发送到另一个进程



我有一个关于进程替换和bash重定向的问题。

考虑

$ zzz > >(echo fine) 2> >(echo error)

我期望输出fine error,因为zzz不是一个有效的命令,但我只得到了fine。为什么会这样?

这符合预期

$ zzz 2> >(echo error)
error

如果我交换订单

$ zzz 2> >(echo error) >(echo fine)
fine
error
这是因为bash将输出重定向(> >(echo fine)部分)应用于echo error进程以及zzz命令本身。由于CCD_ 6对该输入不做任何事情;错误";文本只是消失了。您可以通过将echo fine替换为实际显示其输入内容的东西来看到这一点:
$ zzz > >(sed 's/^/processed through sed: /') 2> >(echo error)
$ processed through sed: error

请注意(至少当我尝试它时),这看起来很奇怪,因为shell在sed输出修改后的错误消息之前打印了下一个提示("$")。>( )创建的子流程实际上是后台的,因此shell不会等待它们完成。

如果您想避免这种情况(或者至少解决这种情况),可以将stdout文件描述符复制到另一个FD,然后将其他进程的输出重定向到该备用FD。下面是一个使用FD#3的例子:

$ zzz 3>&1 > >(echo fine) 2> >(echo error >&3)
fine
error

顺便说一句,如果你把重定向按另一个顺序排列,那么重定向到echo fine的逻辑发生在echo error进程启动之后,所以echo fine的输出正常地到达终端。另一方面,如果这样做,那么echo fine命令中的错误将重定向到echo error

$ zzz 2> >(echo error) > >(echo fine; yyy)
error
fine

(在这个例子中,xxxyyy的"未找到命令"错误被发送到echo error,后者忽略它们。)

BTW^2,zsh也实现了进程替换,但不以这种方式应用继承的重定向:

zsh% zzz > >(echo fine) 2> >(echo error)
fine
error

据我所知,进程替换不是由任何标准定义的,所以我不认为有一种方法可以定义哪个shell的实现是"更正确";。

最新更新