Shell脚本中括号内代码是否最后执行?关于文件描述符重定向执行顺序的疑问
拆解这段Shell重定向代码:解答你的两个疑问
让我们一步步把这段有点绕的Shell代码拆明白,直接回应你的两个问题:
疑问一:括号内的内容是否最后执行?
当然不是。这里的(...)是用来创建子shell的语法——括号里的整个命令组会作为一个独立的子进程运行。而外部的3>&1是父Shell在启动这个子Shell之前就会处理的重定向操作,整个执行顺序是:
- 父Shell先处理
3>&1:把文件描述符3(简称fd3)指向当前的标准输出(也就是父进程原本的stdout)。 - 启动子Shell,子Shell会自动继承父Shell的fd3指向关系。
- 子Shell内部执行括号里的命令序列:
cat "$@" 2>&1 >&3 | tr a-z A-Z >&2。
所以括号内的内容是在外部重定向设置完成后才执行的,并不是整个命令里最后执行的部分——最后执行的是子Shell进程结束后,父Shell继续的后续流程。
疑问二:先执行3>&1还是>&3?
作业答案的解释是对的,我们把逻辑理得更清晰些:
Shell处理重定向有个核心规则:从左到右解析,先处理最外层的重定向,再处理子命令/子Shell内部的重定向。
针对你的代码(cat "$@" 2>&1 >&3 | tr a-z A-Z >&2) 3>&1,具体步骤是:
第一步:父Shell先处理
3>&1
这一步会创建一个指向原stdout的文件描述符3,这个fd的指向关系会被子Shell继承下来——相当于给原stdout做了个“备份”,后续子Shell里的命令可以通过fd3直接访问原stdout。第二步:子Shell启动,处理内部的管道和重定向
- 先看管道左边的
cat "$@" 2>&1 >&3:Shell从左到右处理这里的两个重定向:- 先执行
2>&1:把cat的stderr(fd2)重定向到当前的stdout(此时还是子Shell默认的stdout,也就是父Shell的原stdout,但马上会被修改)。 - 再执行
>&3:把cat的stdout(fd1)重定向到fd3(也就是刚才父Shell备份的原stdout)。
- 先执行
- 这样一来,
cat的正常输出(原本的stdout)会直接通过fd3回到父Shell的原stdout;而cat的错误输出(原本的stderr)被转到了管道左侧的stdout,接着通过管道传给右边的tr。 - 管道右边的
tr a-z A-Z >&2:把tr处理后的大写内容(也就是cat的错误输出)重定向到stderr(fd2)。
- 先看管道左边的
总结一下:3>&1是先执行的,它为后续子Shell里的>&3提供了指向原stdout的“通道”,子Shell里的>&3是在这个通道建好之后才执行的。
内容的提问来源于stack exchange,提问作者pelican
相关产品推荐
相关产品推荐

