0
$ cat input.txt
abc
$ sed -e '/PLACE_HOLDER/ {
    s/PLACE_HOLDER//g
    r input.txt
}' <<< '<div>PLACE_HOLDER</div>'
<div></div>
abc

I try to replace PLACE_HOLDER with the content of a file. But it pastes the file content after the matching line. How to just replace the match?

This is not a duplicate of Use the contents of a file to replace a string using SED

  • none of the answers there answer my question specifically. For the 2nd one, which use a bash variable. It is not appropriate when the file is very large. For the first one does not have the problem in my example. In fact, my code is exactly the same as the first answer.
tripleee
  • 175,061
  • 34
  • 275
  • 318
user1424739
  • 11,937
  • 17
  • 63
  • 152

3 Answers3

0

This might work for you (GNU sed):

sed -i 's/PLACE_HOLDER/$(cat input.txt)/g;s/.*/echo "&"/e' file

Substitute the evaluated expression cat input.txt for each match of PLACE_HOLDER globally throughout file.

potong
  • 55,640
  • 6
  • 51
  • 83
  • Specifically, the `e` option to run an external command is a GNU extension, and not portable to other `sed` implementations. – tripleee Dec 26 '22 at 10:06
  • My sed is `$ sed --version sed (GNU sed) 4.8`. But I get error `$ sed -i 's/PLACE_HOLDER/cat input.txt/ge' file.txt sh: -c: line 0: syntax error near unexpected token `newline' sh: -c: line 0: `
    cat input.txt
    '`. What is wrong?
    – user1424739 Dec 26 '22 at 16:18
  • With GNU sed 4.9 I get ```/bin/sh: -c: line 0: syntax error near unexpected token `newline'``` and ```/bin/sh: -c: line 0: `
    cat input.txt
    '```
    – Ed Morton Dec 26 '22 at 18:51
  • Ooops!. My testing was inadequate. See edit. – potong Dec 27 '22 at 10:32
0

Like you discovered, the r command inserts new lines after the current line. That's not suitable if you want to embed the contents of another file in the middle of other text on the same line which should not be replaced.

A crude fix is to build a sed script from your input file. Notice then that any & characters in the input file have to be escaped, as well as any literal newlines.

Because we will be escaping ampersands, I decided to use that as the separator for the s command, too.

sed 's/\&/\\&/g
     1s/^/s\&PLACE_HOLDER\&/
     $!s/$/\\/
     $s/$/\&/' input.txt |
sed -f - targetfile

Unfortunately, because standard input is tied to -f - your script can't process standard input for replacements. A simple workaround for that is to save the generated sed script to a temporary file and pass that as the value for the -f option; this will also be necessary if your sed is one which does not accept the script on standard input.

I believe this should be reasonably portable, apart from the notes about -f - above.

Demo: https://ideone.com/oVgIni

tripleee
  • 175,061
  • 34
  • 275
  • 318
0

Using any awk:

$ awk '
    BEGIN { old="PLACE_HOLDER" }
    NR==FNR { new=(NR>1 ? new ORS : "") $0; next }
    s=index($0,old) { $0=substr($0,1,s-1) new substr($0,s+length(old)) }
    { print }
' input.txt - <<< '<div>PLACE_HOLDER</div>'
<div>abc</div>

The above will work no matter which characters are present in the string you want to match or the file you want to replace it with.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185