额外的()或{}如何改变Bash中重定向到/dev/null的内容?
Bash文件描述符重定向:嵌套括号为何改变输出?
我在测试Bash文件描述符重定向时发现两个命令输出结果截然不同:
命令1:
((echo STDOUT; echo STDERR >&2;) 3>&1 1>&2 2>&3 3>&-) 2> /dev/null
命令2:
(echo STDOUT; echo STDERR >&2;) 3>&1 1>&2 2>&3 3>&- 2> /dev/null
我原本预期前者因stdout和stderr交换输出STDERR,后者输出STDOUT,但实际结果相反。额外的一层括号为何会改变输出?
编辑补充:文件描述符流向逻辑梳理
经解释后,两种场景的文件描述符指向逻辑如下:
场景1:双层括号((...))
- 初始状态:
1指向终端标准输出,2指向终端标准错误 - 先处理内层子shell的交换重定向
3>&1 1>&2 2>&3 3>&-,完成1和2的指向互换:此时1指向原标准错误,2指向原标准输出 - 再处理外层的
2> /dev/null,将当前的2(原标准输出)重定向到/dev/null - 执行命令:
echo STDOUT:写入当前1(原标准错误),最终输出到终端echo STDERR >&2:写入当前2(/dev/null),被丢弃
→ 最终输出STDOUT
场景2:单层括号(...)
- 初始状态:
1指向终端标准输出,2指向终端标准错误 - 先处理命令最后的
2> /dev/null,将当前2重定向到/dev/null - 再处理子shell的交换重定向
3>&1 1>&2 2>&3 3>&-,完成1和2的指向互换:此时1指向/dev/null,2指向原标准输出 - 执行命令:
echo STDOUT:写入当前1(/dev/null),被丢弃echo STDERR >&2:写入当前2(原标准输出),最终输出到终端
→ 最终输出STDERR
核心差异在于重定向的执行顺序:双层括号时,交换重定向先于2> /dev/null执行;单层括号时,2> /dev/null先于交换重定向执行,导致交换的是已经被重定向的描述符。
内容的提问来源于Stack Exchange,提问作者Adrian
相关产品推荐
相关产品推荐

