考虑
$ 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
具有相同的效果。