26

I have a text file (devel.xml).

I added the word REPLACETHIS to it in order to replace this string with the content within a different file (temp.txt).

The closest thing I have is this:

sed -i -e "/REPLACETHIS/r temp.TXT" -e "s///" devel.txt;

This inserts the content after the string, and then deletes the string afterwards.

Is this the best way to do it?

1
  • 2
    Does it have to be sed? Depending on how much text is in temp.txt, I might step up to a perl solution.
    – user17591
    Commented Sep 28, 2012 at 14:24

3 Answers 3

44

What you've done is to remove SUBSTITUTETHIS wherever it appears in the file (but not the rest of the line where it appears) and insert the content of temp.TXT below that line. If SUBSTITUTETHIS appears multiple times on a line, only the first occurrence is removed, and only one copy of temp.TXT is added.

If you want to replace the whole line when SUBSTITUTETHIS appears, use the d command. Since you need to run both r and d when there's a match, put them in a braced group.

sed -e '/SUBSTITUTETHIS/ {' -e 'r temp.TXT' -e 'd' -e '}' -i devel.txt

Some sed implementations let you use semicolons to separate commands and omit separators altogether around braces, but you still need a newline to terminate the argument to the r command:

sed -e '/SUBSTITUTETHIS/ {r temp.TXT
                          d}' -i devel.txt

If you want to replace SUBSTITUTETHIS by the content of the file, but retain what comes before and after it on the line, it's more complicated. The simplest method is to include the content of the file in the sed command; note that you'll have to properly quote its contents.

sed -e "s/SUBSTITUTETHIS/$(<temp.TXT sed -e 's/[\&/]/\\&/g' -e 's/$/\\n/' | tr -d '\n')/g" -i devel.txt

Or use Perl. This is short but runs cat once for each substitution:

perl -pe 's/SUBSTITUTETHIS/`cat temp.TXT`/ge' -i devel.txt

To read the file once when the script starts, and avoid depending on a shell command:

perl -MFile::Slurp -pe 'BEGIN {$r = read_file("temp.TXT"); chomp($r)}
                        s/SUBSTITUTETHIS/$r/ge' -i devel.txt

(presented on two lines for readability but you can omit the line break). If the file name is variable, to avoid quoting issues, pass it to the script via an environment variable:

replacement_file=temp.TXT perl -MFile::Slurp -pe 'BEGIN {$r = read_file($replacement_file); chomp($r)}
                        s/SUBSTITUTETHIS/$r/ge' -i devel.txt
5
  • How could I change the perl command so that instead of cat temp.txt I could do cat ${variable}? Commented Aug 30, 2017 at 23:38
  • @MariaInesParnisari I made a mistake with comment formatting. See my answer, with a slightly different, more robust solution. Commented Aug 31, 2017 at 18:25
  • Since File::Slurp is not always installed, an alternative is to use the -0777 switch to slurp in the whole file, and a regular open : perl -0777 -pe 'BEGIN {open F, q(temp.TXT); $r=<F>; chomp($r)} s/SUBSTITUTETHIS/$r/ge' -i devel.txt
    – mivk
    Commented Mar 4, 2019 at 22:12
  • How to wrap r temp.TXT with messages like "BEGIN temp.TXT", "END temp.TXX"
    – kyb
    Commented May 23, 2019 at 10:10
  • I found solution for my question. Use a (add) command. grymoire.com/Unix/Sed.html#uh-36
    – kyb
    Commented May 23, 2019 at 10:41
1
sed 's/<\!--insert \(.*\.html\) content here-->/&/;s//\ncat "\1"/e'

or this more concise and (I suspect) more efficient refinement from @KlaxSmashing:

sed 's/<\!--insert \(.*\.html\) content here-->/\ncat "\1"/e'

This is a one-liner templating system I made for inserting html partials into another html file. It lets you specify a filename within a pattern. That pattern is then replaced with the content from the filename specified in the pattern.

For example, the line <!--insert somehtmlfile.html content here--> gets replaced with the content of somehtmlfile.html. It appears to work fine without any special handling for characters like & or \.

$ cat first.html
first line of first.html
second line of first.html

$ cat second.html
this is second.html
\ slashes /
and ampersand &
and ! exclamation point
end content from second.html

$ cat file\ name\ space.html
the file containing this content has spaces in the name
and it still works with no escaping.

$ cat input
<!--insert first.html content here-->
input line 1
<!--insert first.html content here-->
input line 2
<!--insert second.html content here-->
input line 3
<!--insert file name space.html content here-->

$ sed 's/<\!--insert \(.*\.html\) content here-->/&/;s//\ncat "\1"/e' input
first line of first.html
second line of first.html
input line 1
first line of first.html
second line of first.html
input line 2
this is second.html
\ slashes /
and ampersand &
and ! exclamation point
end content from second.html
input line 3
the file containing this content has spaces in the name
and it still works with no escaping.

$
3
  • 1
    This concise solution works best for me. But it can be simplified. 1st subst = s/../&/ leaves line unchanged because of & replacement. 2nd subst = s// uses the previous pattern and so matches again and uses cat as replacement. So a shorter expression can be written as: sed 's/<\!--insert \(.*\.html\) content here-->/\ncat "\1"/e' Commented Jul 12, 2023 at 18:07
  • How do you control the order-of-insertion of *.html file text? Commented Jul 17, 2023 at 7:45
  • 1
    @jubilatious1 it's parsing the filename out of the pseudo-comment line; see the sentence starting with "For example". Looking at it again I see how naming the files first, second, third make it seem like there's an implied order there, but you can name the files arbitrarily. Commented Jul 24, 2023 at 16:30
0

Using Raku (formerly known as Perl_6)

~$ raku -pe 'BEGIN my $donor_file = "donor_file.txt".IO.slurp;   \
             s:g/REPLACETHIS/{$donor_file}/;'  recipient_file.txt

This Raku answer uses the familiar s/// substitution idiom, and -pe autoprinting (sed-like) flags are used.

In the first statement the donor_file.txt is slurped (read all-at-once) into the $donor_file variable. In the second statement the :g adverb tells s/// to perform a :global substitution. On the RHS of the substitution operator (replacement half), enclosing the $donor_file variable in {…} curly braces triggers interpolation, inserting the desired text.

https://raku.org

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .