Replace a marker in a text file with arbitrary new text

awksedtext processing

I have a file which contains some text and – on a single line – a marker which indicates where new content should be added

foo
bar
%SUBSTITUTE%
foo

The line line substitute should be replaced by a new multiline string text="some text" (note that I do not know the string it may for instance be the result of reading a file text=cat "file"“). The result of the replacement should read

foo
bar
some text
%SUBSTITUTE%
foo

I had a working version based on perl which stopped working (apparently due to perl version change). Now I am trying standard utilities like tr and sed to replace the line.
I am having some trouble with it, because the string to be pasted may contain arbitrary characters including backslashes etc. I do not want to escape these before pasting.

Is there a safe way to do it which works with standard tools? The other questions I find for the problem are particular solutions where the text to be pasted is known.

Best Answer

If you have the GNU version of sed, you should be able to use the r command to read and insert new content from a file, then delete the marker line e.g.

sed '/%SUBSTITUTE%/{
r path/to/newcontent
d
}' file

If you want to retain the %SUBSTITUTE% marker after the insertion, that's tricky because whatever you do, the GNU r extension queues the file contents until the end of the current pattern cycle (retaining it before would just be a matter of removing the d command). Probably the simplest way is to append it to the newcontent file: you could do that on the fly like

sed '/%SUBSTITUTE%/{
r /dev/stdin
d
}' file < <(sed '$a %SUBSTITUTE%' path/to/newcontent)

Taking a completely different approach, you could split the first file on %SUBSTITUTE% and then cat in the new content

csplit -s file '/%SUBSTITUTE%/'
cat xx00 newcontent xx01

You could also do a bash read loop over the lines of the first file, and cat the new content file when you match the marker string - however I've had my knuckles rapped for suggesting read loops for text processing on this forum. Unfortunately neither provides an in-place solution.