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

link|improve this question

56% accept rate
Your question isn't clear. Do you want to add testmo\n before </body> and then at some later date change testmo to file.txt? – Iain May 7 '11 at 8:24
i want to add text from file.txt before </body> – user47556 May 7 '11 at 8:39
file.txt include like 4 lines – user47556 May 7 '11 at 8:39
feedback

4 Answers

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.

link|improve this answer
The sed-fu is stronger in this one! – Iain May 7 '11 at 23:13
1  
Haha! Definitely not, I only came to this after reading your answer. – Eduardo Ivanec May 7 '11 at 23:15
This is a great solution - thanks. – Iain May 7 '11 at 23:31
I've been scouring the toobs for this info, ++ – Sophistifunk Aug 4 '11 at 4:14
feedback

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 {} \;
link|improve this answer
1  
Ooooh, cunning! The sed-fu is strong in this one. – MadHatter May 7 '11 at 21:59
1  
This is quite nice. I think you can do it without the marker text though, I posted that variation as a separate answer. – Eduardo Ivanec May 7 '11 at 23:05
feedback

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.

link|improve this answer
2  
+1 for creative excuse to use perl oneliner. – Caleb May 7 '11 at 13:18
feedback

Sed version:

find ./ -name 1.php -exec sed -i 's/<\/body>\/testmoe\\n<\/body>/<\/body>\/file.txt\\n<\/body>/g'{} \;
link|improve this answer
Forgive me, Ruslan, but I think that just replaces the text testmoe with the text file.txt, doesn't it? If I understand the OP correctly, he wants to put the contents of file.txt into the place where the text testmoe was. I apologise in advance if my sed-fu is weak, and your sed invocation does the latter. – MadHatter May 7 '11 at 9:36
Madhatter your correct , I want to put contents of file.txt before close </body> – user47556 May 7 '11 at 9:52
oh, sorry, did no get question – Ruslan May 7 '11 at 10:01
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.