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:
perl -n
loops through STDIN line-by-line; for each line -e
invokes the script in single-quotes, in which:
$temp = $_
stores the line in a temporary buffer
if ( $_ =~ /<\/body>/ )
looks for a line containing </body>
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
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.
testmo\n
before</body>
and then at some later date changetestmo
tofile.txt
?