sed insert from file.txt to multi files

I've this sed & find command

find /home/www/ -name footer.php -exec sed -i 's/<\/body>/testmoe\n<\/body>/'

what I need to replace testmoe with data in file.txt so its gona be ,

find /home/www/ -name footer.php -exec sed -i 's/<\/body>/file.txt\n<\/body>/'

any suggestion to correct my command


To improve a little on @Iain's answer, I think you can do it in just one pass like this:

#!/bin/sh
sed -i '/<\/body/ {
    r /path/to/file
    a </body>
    d
}' $1

This searches for </body>, inserts the file into the buffer, appends </body> to the buffer, and then deletes the original </body>, which as Iain correctly pointed out can't be moved.


With sed you have to make multiple passes as the /RE/r <filename> command inserts the contents of <filename> into the output after the /RE/. The easiest way to do this with sed is to

  • Insert 'marker text' before the /RE/ in pass one
  • Insert the contents of the file after the 'marker text' in pass two
  • Delete the 'marker text' in pass three

This is most easily achieved with a script which you can call from find

#!/bin/bash

sed -i '/<\/body>/i xyzzy' $1
sed -i '/xyzzy/r /path/to/file.txt' $1
sed -i  '/xyzzy/d' $1

then

find /home/www -name footer.php -exec /path/to/script {} \;

I know it's a bit like the old West Country joke ("Do you know how to get to Yeovil?" "If I wanted to get to Yeovil, I wouldn't start from here, sir.") but I wouldn't use sed.

Try

perl -ne '$temp = $_ ; if ( $_ =~ /<\/body>/ ) { open FD2, "file.txt" ; while (<FD2>) { print  $_ ; } } ; print $temp;' < foo > bar

perl one-liners can be a bit, well, cryptic, so here's a breakdown of what's happening. The perl script:

  1. perl -n loops through STDIN line-by-line; for each line -e invokes the script in single-quotes, in which:
  2. $temp = $_ stores the line in a temporary buffer
  3. if ( $_ =~ /<\/body>/ ) looks for a line containing </body>
  4. open FD2, "file.txt" ; while (<FD2>) { print $_ ; }: when </body> has been found, opens a file descriptor to file.txt and in a subloop reads through each line in that file and writes it to STDOUT; the re-use of $_ in this loop is why we had to temporarily store it in step 2
  5. print $temp; writes the line originally read to STDOUT regardless of whether a match was found in step 3

The practical upshot is that each line of STDIN is written to STDOUT, but if any line happens to contain </body>, the entire contents of file.txt are inserted before that line is written out.

Is that what you wanted? If so, wrapping it in find, redirecting STDIN and STDOUT, and renaming STDOUT on top of STDIN after execution, is left as an exercise for you. You should also note that if you happen to have more than one occurrence of </body> in your file, you'll get the contents of file.txt intercalated each time it occurs.