从Unix猫redirect文件到自己的无限循环

我试图将许可证连接到我的内置源代码的顶部。 我使用GNU Make。 在我的一个规则中,我有:

cat src/license.txt build/3d-tags.js > build/3d-tags.js 

但是这似乎正在造成一个无限循环。 当我杀死cat命令时,我发现build / 3d-tags只是src / license.txt的内容一遍又一遍? 这是怎么回事? 我会怀疑这两个文件被连接在一起,并从cat产生的输出被redirect到build / 3d-tags.js。 我不想追加。 我在OSX上,如果这个问题是关于GNU猫对BSD猫。

shell将cat作为子进程启动。 输出重定向( > )被该子进程作为其stdout(文件描述符1)继承。 由于子进程在创建时必须继承文件描述符,因此在启动子进程之前,shell必须打开输出文件。

所以,shell打开build/3d-tags.js来编写。 此外,由于您不追加( >> ),所以会截断该文件。 请记住,这种情况发生在cat甚至被启动之前。 此时,由于build/3d-tags.js的原始内容已经不存在,所以不可能达到你想要build/3d-tags.jscat甚至还没有发布。

然后,当cat启动时,它打开其参数中命名的文件。 打开它们的时间和顺序并不是非常重要。 当然,它打开了他们的阅读。 然后从src/license.txt读取并写入其stdout。 这个写作去build/3d-tags.js 。 在这一点上,它是该文件中唯一的内容,因为它之前被截断。

然后catbuild/3d-tags.js 。 它查找刚刚写入的内容,这是以前从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 

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