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