从Unix cat重定向文件到自身时的无限循环

Nic*_*ers 2 unix macos bsd cat io-redirection

我正在尝试将许可证连接到我构建的源代码顶部.我使用的是GNU Make.在我的一条规则中,我有:

cat src/license.txt build/3d-tags.js > build/3d-tags.js
Run Code Online (Sandbox Code Playgroud)

但这似乎导致了无限循环.当我杀死cat命令时,我看到build/3d-tags一次又一次只是src/license.txt的内容?这是怎么回事?我怀疑这两个文件是连在一起的,并且将cat产生的输出重定向回build/3d-tags.js.我不打算追加.我在OSX上,以防问题与GNU cat vs BSD cat有关.

Ken*_*ses 5

shell cat作为子进程启动.输出重定向(>)由该子进程作为其stdout(文件描述符1)继承.由于子进程在其创作继承文件描述符,它遵循的外壳具有启动子之前打开输出文件.

所以,shell打开build/3d-tags.js写作.此外,由于您没有附加(>>),它会截断文件.请记住,这cat甚至在发布之前就已经发生了.此时,由于原始内容build/3d-tags.js已经消失,cat甚至尚未启动,因此无法实现您想要的效果.

然后,在cat启动时,它会打开其参数中指定的文件.它打开它们的时间和顺序并不是非常重要.当然,它会打开它们进行阅读.然后src/license.txt它从其stdout 读取和写入.写这篇文章build/3d-tags.js.此时,它是该文件中唯一的内容,因为它之前被截断了.

cat然后读取build/3d-tags.js.它找到刚刚写入的内容,这是cat之前读过的内容src/license.txt.它将内容写入文件的末尾.然后回去尝试阅读更多内容.当然,它会更多地阅读,因为它只是在文件的末尾写了更多的数据.它读取剩余数据并将其写入文件.等等.

为了cat按照你的意愿工作(甚至忽略了shell重定向,删除了内容build/3d-tags.js),它必须读取并保留内存中的所有内容build/3d-tags.js,无论它有多大,以便它可以在写入后写入的内容src/license.txt.

实现你想要的最好的方法可能是这样的:

cat src/license.txt build/3d-tags.js > build/3d-tags.js.new && mv build/3d-tags.js.new build/3d-tags.js || rm -f build/3d-tags.js.new
Run Code Online (Sandbox Code Playgroud)

即:将两个文件连接到一个新文件; 如果成功,将新文件移动到原始文件名(替换原始文件); 如果任一步失败,请删除临时"新"文件,以免留下垃圾.