0

I needed to append some text to a bunch of files in a directory, so I thought I'd be clever and try something like this:

find . -name "*.txt" -exec cat source >> {} \;

Which did not work, of course, because the redirect gets picked up by the shell calling find, and not by the exec.

I ended up using BBEdit and a multi-file find/replace to do it, but I am sure there's some way to make find do this from the command line, but what?

Well, OK, I can think of one solution, but I don't like it: have exec spawn a shell for each result. That might work.

modusCell
  • 13,151
  • 9
  • 53
  • 80
lbutlr
  • 414
  • 6
  • 18
  • 1
    Is it just a directory without subdirectories? If so, you can do: `for file in /your/dir/*.txt; do cat source >> "$file"; done` – fedorqui Aug 18 '14 at 08:20

2 Answers2

3

What about :

find . -name "*.txt" -exec dd if=source of='{}' oflag=append conv=notrunc ';'

You should be able to use it with files with spaces and special characters.

Vouze
  • 1,678
  • 17
  • 10
2

You have at least two options:

find . -name "*.txt" -exec sh -c 'f={}; cat source >> $f' \;
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This executes the command invoking the exec function of find. Note it would be also convenient to use -type f just to match files.

Or you can use a simple for loop, that will loop through all the files matching the pattern *.txt:

for file in *.txt
do
    cat source >> "$file"
done
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • yeah, spawning a shell for each matched file seems like a bad idea if it's more than a few hundred files, but maybe that's just because I was 'raised' on a system with probably 16MB of RAM for 40 users. – lbutlr Aug 18 '14 at 08:27
  • Yes, true, in such case it is not a very good idea. However, I don't know how it will perform the `for file in *.txt` if it matches hundred of items -maybe you get the "too many arguments" error. Let us know how it works! – fedorqui Aug 18 '14 at 08:30
  • What if I create a file named "David's file.txt" – Vouze Aug 18 '14 at 14:55
  • 1
    With bash "for file in *.txt" is not expanded. So you will never have "too many arguments". – Vouze Aug 18 '14 at 14:59
  • @Vouze oh, you are right about the "too many arguments". Regarding the file named with some single quotes, in such case we should look for other ways (yours with `dd` could be one), but I think it is quite unlikely to happen and I prefer to leave the solution right how it is now. But thanks for pointing it and +1 for your approach. – fedorqui Aug 18 '14 at 15:07
  • The loop version will not descend into subdirectories; with `bash` 4, you can fix that by running `shopt -s globstar` and changing the loop to `for file in **/*.txt`. – chepner Aug 18 '14 at 17:05