为什么shell重定向与find奇怪地相互作用

时间:2012-03-16 18:22:31

标签: shell find sh

我想在* nix目录和任何子目录中的每个.java文件的前面添加一个许可证文件。我有这个解决方案,似乎工作正常:

$ cat muppet-license.txt 
// LICENSE: // Manuh-manuh
$ for file in `find . -iname "*.java"`; do 
     cat muppet-license.txt "$file" > "$file.out"; 
     mv "$file.out" "$file";
done

我的问题是,为什么以下查找调用不起作用:

find . -iname "*.java" -exec sh -c 'cat muppet-license.txt "$1" > "$1"' -- {} \;

这导致find找到的第一个文件将“muppet license”重复添加到它的前面 - 该文件似乎在不停止的情况下不断增长。

有人可以解释一下造成这种差异的原因是什么?是否与修改名为$ 1的文件有关,导致find重新找到它作为递归搜索的一部分?有没有人对找到用途的算法的细节有任何好的参考?

3 个答案:

答案 0 :(得分:3)

你告诉cat要从你写的同一个文件中读取:

cat muppet-license.txt "$1" > "$1"

因此,cat会读取muppet-license.txt并将其写入$1,然后阅读$1(现在包含许可证)并将许可证再次附加到同一文件的末尾,然后继续阅读已写入的内容,等等,在$1内一遍又一遍地复制许可文件......

这样的事情应该有效:

find . -iname "*.java" -exec sh -c 'cat muppet-license.txt "$1" > "$1.out"; mv "$1.out" "$1"' -- {} \;

通过将许可证和$1写入单独的文件$1.out并在写入后将其移回$1,可以避免无限循环。差异与find无关,只与sh和cat的调用有关。

答案 1 :(得分:3)

问题在于

cat foo $file > $file

将完全按照你的要求去做,这并不总是显而易见的。 shell执行该命令的第一件事是打开$file进行写入,从而将其截断为零长度。然后运行cat,将foo$file的内容连接到$file,这些内容现在是foo的副本。

答案 2 :(得分:1)

问题不在于查找。如果您执行以下操作,则会发生相同的行为:

cat muppet-license.txt a.java > a.java

是因为cat正在重新读取它正在编写的数据。 shell打开a.java进行写入,将其截断为零长度。然后cat将muppet-license.txt的内容写入a.java,然后打开a.java(现在是muppet-license.txt的副本),并将第一行写入文件的末尾(第2行)线)。然后它读取第二行并将其追加到末尾(写入第3行),并连续重复。

相关问题