【问题标题】:What is the extra set of () or {} doing to change what gets redirected to /dev/null?额外的一组 () 或 {} 用来改变重定向到 /dev/null 的内容是什么?
【发布时间】:2022-11-29 13:18:05
【问题描述】:
我根据对文件描述符重定向的理解对 bash 进行了一些测试,发现:
((echo STDOUT; echo STDERR >&2;) 3>&1 1>&2 2>&3 3>&-) 2> /dev/null
和
(echo STDOUT; echo STDERR >&2;) 3>&1 1>&2 2>&3 3>&- 2> /dev/null
给出了不同的结果。第一个给出 STDERR 的预期输出,因为交换了 stdout 和 stderr fds,但是第二个给出了 STDOUT 的意外输出,就好像 fds 一开始就没有交换过一样。
这对我来说是令人惊讶的。在这种情况下,我看不到额外的 parenetical 会做什么来改变输出。使用大括号具有相同的效果。
【问题讨论】:
标签:
bash
file-descriptor
io-redirection
【解决方案1】:
重要的是要知道首先处理重定向,即使它们写在命令的末尾也是如此。尽管 2> /dev/null 位于行尾,但它实际上是在子 shell 启动之前执行的。这意味着在第一个示例中它在描述符交换之前执行,但在第二个示例中执行在交换之后。
让我们深入探讨一下。
带外子壳
((echo STDOUT; echo STDERR >&2;) 3>&1 1>&2 2>&3 3>&-) 2> /dev/null
这相当于:
2>/dev/null (3>&1 1>&2 2>&3 3>&- (echo STDOUT; >&2 echo STDERR))
步骤是:
-
2> /dev/null:fd 2 被重定向到/dev/null。
- 外部子外壳启动。
-
3>&1 1>&2 2>&3 3>&-:fds 1 和 2 被交换了。
- 内部子外壳启动。
-
echo STDOUT:写入fd 1,即/dev/null。
-
>&2:fd 1 被重定向到 fd 2,这是原始 shell 的标准输出。
-
echo STDERR:写入 fd 2,即标准输出。
没有外子壳
(echo STDOUT; echo STDERR >&2;) 3>&1 1>&2 2>&3 3>&- 2> /dev/null
这相当于:
3>&1 1>&2 2>&3 3>&- 2>/dev/null (echo STDOUT; >&2 echo STDERR))
步骤是:
-
3>&1 1>&2 2>&3 3>&-:fds 1 和 2 被交换了。
-
2>/dev/null:fd 2 被重定向到/dev/null。
- 子外壳启动。
-
echo STDOUT:写入 fd 1,这是原始 shell 的 stderr。
-
>&2:fd 1被重定向到fd 2,也就是/dev/null。
-
echo STDERR:写入隐藏的 fd 2。