终端读写同一文件时,为何>会致文件为空而>>正常?
问题解析:重定向与tee的行为差异
场景复现
假设有文件foo,内容为:
1 2 3 4 5
- 执行
cat foo | grep 1 > foo后,foo被清空,wc foo输出0 0 0 foo - 执行
cat foo | grep 1 >> foo,foo会保留原内容并追加一行1 - 执行
cat foo | tee foo,文件内容不会被清空
疑问
为什么>重定向会清空文件而非保留grep的结果?tee的行为又为何不同?
一、>重定向清空文件的底层逻辑
shell处理管道+重定向的顺序是先初始化所有重定向,再执行管道中的命令,这是核心原因:
- 当你输入
cat foo | grep 1 > foo时,shell第一步就处理> foo:它会打开foo文件,并执行截断操作——把文件长度直接设为0,此时文件已经是空的了。 - 之后shell才启动
cat foo和grep 1进程:cat去读已经被清空的foo,读不到任何内容,grep自然没有输出,最终foo就保持空状态。
而>>是追加模式,shell打开文件时只会把文件指针移到末尾,不会截断内容,所以cat能正常读取原文件内容,grep筛选出的1会追加到文件末尾,符合预期。
二、tee foo不会清空文件的原因
tee的执行流程和直接重定向完全不同:
- 管道启动后,
cat foo会先把整个文件的内容读进内存,然后通过管道发送给tee——这一步发生在tee修改foo之前。 tee接收到管道传来的内容后,才会打开foo进行写入。此时原文件内容已经被cat读取完毕,tee只是把接收到的原内容重新写入foo,所以看起来文件没有被清空。
如果原文件极大,cat还没读完所有内容时tee就开始写入,可能会出现内容重叠或混乱,但小文件下cat瞬间就能完成读取,最终文件内容和原内容一致。
内容的提问来源于stack exchange,提问作者ffff
相关产品推荐
相关产品推荐

