Reputation:
I want to add a license file to the front of every .java file in a *nix directory and any subdirs. I have this solution, which seems to work fine:
$ 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
My question is, why does the following find invocation NOT work:
find . -iname "*.java" -exec sh -c 'cat muppet-license.txt "$1" > "$1"' -- {} \;
This causes the very first file found by find to have the "muppet license" repeatedly added to the front of it - the file seems to continually grow without stopping.
Can someone explain what's causing the difference here is? Is it something to do with the modification of the file called $1 causing find to re-find it as part of the recursive search? Does anyone have any good references to the details of the algorithm that find uses?
Upvotes: 0
Views: 90
Reputation: 7058
You are telling cat to read from the same file as you are writing to:
cat muppet-license.txt "$1" > "$1"
So cat will read muppet-license.txt
and write it to $1
, then read $1
(which now contains the license) and append the license again to the end of the same file, then continue reading what has been written, and so forth, in an endless loop replicating the license file within $1
over and over...
Something like this should work:
find . -iname "*.java" -exec sh -c 'cat muppet-license.txt "$1" > "$1.out"; mv "$1.out" "$1"' -- {} \;
This avoids the endless loop by writing the license and $1
to a separate file $1.out
and moving it back to $1
after writing to it. The difference has nothing to do with find, only with the invocation of sh and cat.
Upvotes: 3
Reputation: 212248
The problem is not with find. The same behavior occurs if you do:
cat muppet-license.txt a.java > a.java
and is because cat is re-reading the data it is writing. The shell opens a.java for writing, truncating it to zero length. cat then writes the contents of muppet-license.txt into a.java, and then opens a.java (which is now a copy of muppet-license.txt), and writes the first line to the end of the file (the 2nd line). It then reads the 2nd line and appends it the end (writing line 3), and repeats continuously.
Upvotes: 2
Reputation: 43497
The problem is that
cat foo $file > $file
will do exactly what you tell it to do, which is not always obvious. The first thing the shell does with that command is opens $file
for writing thus truncating it to zero length. Then cat
is run, concatenating foo
and the contents of $file
which are now a copy of foo into $file
.
Upvotes: 3