Bash重定向一个重定向回自身的替代进程



考虑

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

我本来以为这会一直打印"错误"到终端,因为我认为这就是这里正在发生的事情:

首先设置所有重定向:

  • 将stdout重定向到>(回声精细)过程
  • 将stderr重定向到>(回波误差>&2)处理

设置所有重定向后,执行zzz命令:

  • 由于zzz是一个无效命令,因此重定向到>(回波误差>&2)处理
  • echo error >&2重定向到stderr
  • 但是stderr被重定向到>(echo错误>&2)所以这里发生了递归

至少我没想到它会输出fine,因为zzz命令是一个无效命令,所以它不会触发重定向到stdout,>(echo error >&2)也不应该触发重定向到标准输出。

我对此的理解是不完整的/错误的。

你能解释一下1)为什么递归没有发生,2)为什么打印fine吗?

想明白了。

让我们从开始

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

这里的效果与echo error | echo fine相同。

下一个

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

这里的效果与echo fine; echo error >&2相同。因为它们是不相交的(没有一个依赖于另一个),所以它们没有管道。并没有递归,因为echo error >&2只是打印到终端。

如果我们尝试其他方法绕过

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

这与{ echo fine >&2; } 3>&1 1>&2 2>&3 | echo error相同。

如果它们是不相交的

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

这与echo error; echo fine相同。

如果我们包含一个要运行的命令呢?

$ whoami > >(cat) 2> >(echo error)
error
logan

这与{ echo error & whoami; } | cat相同。

的另一个例子

$ whoami > >(sed 's/^/processed: /') 2> >(echo error)
processed: error
processed: logan

你可以把它想象成{ echo error & whoami; } | sed 's/^/processed: /'

如果它们是脱节的呢?

$ whoami > >(sed 's/^/processed: /') 2> >(echo error >&2)
error
processed: logan

这与echo error >&2; whoami | sed 's/^/processed: /'相同。

让我们使用一个无效的命令。

$ BOB 2> >(cat) > >(echo hi >&2)
hi
BOB: command not found

这与{ echo hi >&2 & BOB; } 3>&1 1>&2 2>&3 | cat相同。

如果我们想引入一个自定义文件描述符呢?

$ whoami > >(sed 's/^/processed: /') 3>&1 2> >(echo error >&3)
processed: error
processed: logan

这与{ echo error & whoami; } | sed 's/^/processed: /'相同。这里要小心重定向的顺序很重要!

如果我们在一个替换的过程中混合了有效和无效的命令,该怎么办?

$ > >(echo fine) 2> >(echo error >&2) 2> >(ls;whoami;echo bob >&2)
fine
error

这里我们已经预设了stderr,将"error"打印到终端。因此,ls;whoami部分最终打印"精细"到终端,而echo bob >&2部分则打印"错误"。

同时考虑

$> >(echo fine) 2> >(ls;whoami;BOB)
fine
BOB: command not found

这里的区别在于stderr仍然指向终端。因此,BOB:command not found错误消息只是原封不动地发送到终端。

同时考虑

$ BOB > >(echo fine) 2> >(echo error >&2) 2> >(ls;whoami;echo bob >&2)
fine
error

这与{ ls & whoami & } | echo fine; { echo bob >&2 & BOB; } 3>&1 1>&2 2>&3 | echo error >&2具有相同的效果。