5

I would like to prepend some text to multiple files in bash, I've found this post that deals with prepend: prepend to a file one liner shell?

And I can find all the files I need to process using find:

find ./ -name "somename.txt"

But how do I combine the two using a pipe?

Community
  • 1
  • 1
DEfusion
  • 5,533
  • 5
  • 44
  • 60

4 Answers4

9

You've got several options. Easiest is probably sed:

find ./ -name somename.txt -exec sed -e '1i\
My new text here' {} \;

It'll be faster if you add '2q' to tell it you're done after prepanding the text, and if will happen in place in the file with the -i flag:

find ./ -name somename.txt -exec sed -i .bak -e '2q;1i\
My new text here' {} \;

To prepend multiple lines, you'll need to end each one with a backslash.

That leaves the original files around with a .bak extension.

Harry Cutts
  • 1,352
  • 11
  • 25
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • This one seemed to do it for me, the other good examples inserted the text multiple times (one for each new line I think) I just had to add -type file and change the -e to -i to get sed to update the files. – DEfusion Feb 06 '09 at 16:15
  • Yup. Using 'iText' matches every line, so inserts the text ahead of each line. '1i' matches only the first line. '0a' would do the same. The '2q' isn't really necessary, but keeps sed from having to look at each line and say 'no, this isn't line 1 either'. – Charlie Martin Feb 06 '09 at 20:16
  • Tried this: find . -iname *.java -exec sed -e '1i\ /* * Copyright (c) 2012 Company X, Inc. All Rights Reserved. */ ' {} \; With this result: sed: 3: "1i\\n/*\n* Copyright (c) ...": invalid command code * – mvmn Mar 12 '12 at 12:36
  • 1
    Figured it out - for multiline text that I wanted to insert I had to put \ at end of line if there was another line after. In previous comment there should've been linebreaks as my inserted text has multiple lines. Looks like they got removed, sorry. – mvmn Mar 12 '12 at 13:26
  • 1
    P.S. One problem did remain though - files weren't updated, I just got the output in stdout. Tried this on Mac OS X 10.6. – mvmn Mar 12 '12 at 13:29
  • Solved it. I had to add -i "" - I know it's in your second command, but not in the first one. – mvmn Mar 12 '12 at 13:46
1
find . -name "somefiles-*-.txt" -type f | while read line; do  sed -i 'iThis text gets prepended' -- "$line"; done

or

find . -name "somefiles-*-.txt" -type f | xargs sed -i 'iGets prepended' --

The best (I think):

find . -name "somefiles-*-.txt" -type f -exec sed -i 'iText that gets prepended (dont remove the i)' -- '{}' \;

Thanks for the missing "-hint. I added the important --s then, too.

Johannes Weiss
  • 52,533
  • 16
  • 102
  • 136
  • it's usually better to quote $line ("$line"). Unfortunately filenames with spaces in them are common nowadays... – mitchnull Feb 06 '09 at 15:44
  • This may be a GNU-ism; original sed wants 'i\ followed by a newline, followed by text to be appended. – Charlie Martin Feb 06 '09 at 15:57
  • For #2, you want to use -print0 with find and -0 with xargs to avoid having problems with folders with spaces in their names. For #3, you should use \+ instead of \; to avoid forking a process for each file. – Adam Rosenfield Feb 06 '09 at 16:03
  • 1
    For #3: I've tried and it prepended the new text before *each* line in the original file. I've added '1' right after the `i` flag (like this: `-i 'i1Text...'`) and it worked properly (prepend only once at beginning) – Julien-L Dec 08 '12 at 00:23
-1
find . -name "somename.txt" | while read a; do prepend_stuff_to "$a" ; done

or

find . -name "somename.txt -exec prepend_stuff_to "{}" \;
mitchnull
  • 6,161
  • 2
  • 31
  • 23
-1
find ./ -name "somename.txt" -print0 | xargs -0 -n 1 prepend_stuff_to
Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408