bash文件描述符重复问题:重定向顺序为何影响结果?
Bash重定向顺序问题解析
问题背景
man bash中关于重定向的说明如下:
请注意重定向的顺序非常重要。例如,命令
ls > dirlist 2>&1会将标准输出和标准错误都重定向到文件dirlist,而命令
ls 2>&1 > dirlist仅将标准输出重定向到文件dirlist,这是因为标准错误是在标准输出被重定向到dirlist之前从标准输出复制而来的。
用户的困惑点:
标准错误是在标准输出被重定向到dirlist之前从标准输出复制而来的。
用户的疑问逻辑:
在我看来,>仅表示重定向,比如ls > dirlist会将ls的输出重定向到文件dirlist。那么2>&1应该是将stderr重定向到stdout,而stdout随后会被重定向到dirlist(> dirlist)。但显然此时只有stdout被重定向到dirlist。这里的“流A从流B复制”到底是什么意思?
核心解答
本质:2>&1是复制文件描述符,不是建立关联
2>&1的真实含义是复制当前文件描述符1(stdout)指向的目标,赋值给文件描述符2(stderr)——它是一次性的“复制”动作,不是让stderr永久“跟随”stdout的后续变化。
拆解两个命令的执行流程
1. ls > dirlist 2>&1(实现双流向文件输出)
- 第一步:执行
> dirlist,将stdout(文件描述符1)的默认指向(终端)替换为文件dirlist。 - 第二步:执行
2>&1,把当前stdout指向的dirlist复制给stderr(文件描述符2)。此时stderr也指向dirlist。 - 最终:stdout和stderr的输出都会写入
dirlist。
2. ls 2>&1 > dirlist(仅stdout写入文件)
- 第一步:执行
2>&1,此时stdout还指向终端,所以把“指向终端”这个属性复制给stderr。现在stderr和stdout都指向终端。 - 第二步:执行
> dirlist,将stdout的指向改为dirlist,但stderr的指向已经固定为终端,不会随stdout的变化而更新。 - 最终:只有stdout的内容写入
dirlist,stderr的内容依然输出到终端。
用“指针”类比理解
把文件描述符想象成系统里的“指针”:
2>&1就是复制指针1当前的指向地址给指针2,之后指针1再换指向,指针2不会跟着变。- 不是让指针2一直绑定指针1,只是一次性同步当时的目标。
重定向命令是从左到右依次执行的,每一步操作都基于当前的文件描述符状态,这就是顺序影响结果的根本原因。
内容的提问来源于stack exchange,提问作者LetMeSOThat4U
相关产品推荐
相关产品推荐

