2014-09-30 109 views
1

我试图将许可证连接到我的内置源的顶部。我使用GNU Make。在我的一个规则中,我有:从Unix重定向文件到自己的无限循环cat

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

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

回答

5

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

因此,shell会打开build/3d-tags.js进行写入。此外,由于您没有追加(>>),因此会截断该文件。请记住,这发生在cat甚至已启动之前。此时,由于build/3d-tags.js的原始内容已经消失,并且cat尚未推出,因此无法实现您想要的内容。

然后,当启动cat时,它会打开其参数中指定的文件。它打开它们的时间和顺序并不是非常重要。当然,它可以让他们阅读。然后它从src/license.txt读取并写入其标准输出。写这篇文章去build/3d-tags.js。此时,该文件中的只有内容,因为它之前被截断。

cat然后从build/3d-tags.js读取。它找到刚刚写在那里的内容,这是猫先前从src/license.txt读取的内容。它将该内容写入文件的末尾。它然后回去并尝试阅读更多。当然,它会发现更多需要阅读的内容,因为它只是在文件末尾写入更多数据。它读取这些剩余的数据并将其写入文件。并继续。

为了cat工作,因为你希望(甚至忽略了壳重定向磨灭的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 

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

+0

很酷,感谢您的详细回复。我很感激。这是我第一次看到逻辑或在shell脚本中使用(不是我做了很多shell脚本)! – 2014-09-30 05:10:01