作为 for 循环的一部分写入同一文件会生成一个空文件

作为 for 循环的一部分写入同一文件会生成一个空文件

我正在编写一个命令,将一些文本添加到一堆与特定模式匹配的文件中:

for file in $(find . -name "*.txt"); do sed "1s/^/hello/" $file; done 

如果我写入stdout或不同的文件(例如"$file.bak"),一切都会按计划进行,但是当我尝试让命令写回同一个文件时,文件的内容会被擦除:

for file in $(find . -name "*.txt");do sed "1s/^/hello/" $file > $file; done

我发现这种行为令人惊讶,有人可以从概念上解释为什么会发生这种情况吗?我在 macOS 上尝试过此操作bashzsh达到相同的效果。

(请注意,我知道sed -i ""就地写入,但我想在就地写入之前将结果通过管道传输到不同的命令。)

答案1

概念上的惊喜可能就在这个声明中

但是当我尝试将命令写回同一个文件时

使用时,cmd file > file它不是cmd打开文件来写回,而是打开 shell 本身。 shell 看到时所做的第一件事> file就是在位置 0 处以写入模式打开文件(从而截断它),然后将 stdout 重定向到该文件。所以此刻cmd开始读取file它已经是空的。

或者,更正式一点:

  • Shell fork 一个新进程来cmd运行
  • 新进程(仍在运行 shell 代码)打开file以在位置 0 写入(从而截断它)
  • 新进程执行cmd,实际上在当前进程中启动一个新的二进制文件
  • cmd运行时标准输出指向file
  • cmd打开file阅读,但此时已经空了

另一方面,如果您使用的sed -i '1s/^/hello/' file文件是单独管理的sed(从技术上讲,它会在后台创建一个临时文件)。

相关内容