You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash中无需显式临时文件实现文件写入自身的技巧

问题说明

注意:我专门在寻找代码奇技淫巧方案,而非替代解决方案。我清楚awk、sed等工具可以很好地完成这类内联编辑操作。

问题复现命令:

$ echo '1' > test
$ cat test > test
$ cat test
$ 

直接执行cat test > test会得到空文件,核心原因是shell在启动cat命令前,就会先处理> test重定向,以写模式打开文件并截断所有内容,等cat开始读test的时候,文件已经是空的了。
需求是找到方法让上述第二条命令执行后,文件仍然保留原始内容1,要求无需显式使用二级文件(后台隐式使用二级文件/内核缓冲是允许的),不需要常规的sed -i、awk -i inplace这类通用替代方案。

可实现的奇技淫巧方案

方案1:利用inode引用计数机制(无额外依赖,100%可靠)

这个方案利用POSIX文件系统的核心特性:文件被进程打开持有文件描述符时,即使从目录中被删除(unlink),inode对应的数据块也不会被回收,直到所有指向该inode的文件描述符关闭才会真正清除数据。
最简洁的原生shell写法:

( rm test; cat > test ) < test

执行逻辑无任何竞态:

  • shell启动子shell时,首先处理末尾的< test重定向,以读模式打开原test文件,绑定到子shell的标准输入,此时原文件的inode已经被stdin的文件描述符持有
  • 子shell内先执行rm test,删除test对应的目录项,此时目录里看不到原文件,但原文件的inode和数据因为stdin的引用仍然完整保留
  • 接着执行cat > test:cat默认从标准输入读取原文件的全部内容,同时> test会创建一个和原文件完全无关的新同名文件(分配新inode),把读到的原内容写入新文件
  • 命令执行结束子shell退出,stdin持有的旧文件描述符自动关闭,旧inode因为引用计数归0被系统回收。全程没有显式创建任何临时文件,所有内核层面的操作对用户完全透明,不管文件多大都能稳定工作。

提示:这个技巧仅做玩法展示,如果中途进程被异常终止,原文件已经被删除、新文件未写完会导致数据丢失,重要数据操作请用正规的原地编辑工具。

方案2:用sponge自动缓冲(写法最简洁)

sponge是moreutils工具集里的专用小工具,设计初衷就是解决这类"读文件同时写回同一个文件"的场景,它会自动把所有输入内容读入缓冲(内存不足时自动调用后台临时文件,对用户无感知),等输入完全读取完毕后再写入目标文件,不会提前截断文件。
命令写法:

cat test | sponge test

执行逻辑:

  • 管道左侧的cat test启动读取原文件内容,通过管道传给sponge
  • sponge持续接收所有输入存入缓冲,期间不会操作目标文件
  • 等输入流完全结束(原文件内容全部读完),sponge才打开test文件写入缓冲的内容,全程不需要手动指定临时文件名。
不可靠写法避坑

网上流传的cat <(cat test) >test类写法属于典型的竞态漏洞:在文件非常小的时候可能碰巧成功,但本质是赌进程替换里的cat test能在shell截断文件前读完所有内容,处理大文件时几乎必然出现内容丢失,不要在任何真实场景使用。

内容的提问来源于stack exchange,提问作者Roel Van de Paar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:24:23