Note: The following question is related to this post, but both the focus of the question and the format of the input variable are different (i.e., contents of a multi-line file). Thus, the correct solution is likely different as well.
It appears that replacing a keyword in a string with a multi-line variable via sed
works as long as said variable contains explicit newline characters (\n
).
$ target="foo \n bar \n baz"
$ echo "qux\nquux" > file
$ solution=$(cat file)
$ echo "$solution"
qux\nquux
$ echo $target | sed -e "s|bar|$solution|"
foo \n qux
quux \n baz
However, when I open the file file
in a text editor and substitute the newline character with a linebreak, the replacement with sed fails.
# Newline character was manually replaced with linebreak in texteditor.
$ solution=$(cat file)
$ echo "$solution"
qux
quux
$ echo $target | sed -e "s|bar|$solution|"
sed: -e expression #1, char 9: unterminated `s' command
How do I have to change the sed-command to conduct the sought substitution when the input variable that does not have explicit newline characters?
sed
is not necessarily the appropriate tool for this particular job. Consider the below options -- the samples for each of which expect the following setup:
# Run this before testing any of the code below
source='bar'
target='This string contains a target: <bar>'
solution='This has
multiple lines
and /slashes/ in the text'
...and each of which will emit the following output:
This string contains a target: <This has
multiple lines
and /slashes/ in the text>
Note that with sed
, you would need to choose a delimiter that isn't used for the expression (thus, with s/foo/bar/
, neither foo
nor bar
can contain a /
); the below answers both avoid this limitation.
The shell can perform the relevant substitution with only built-in string manipulation functionality:
result=${target//$source/$solution}
echo "$result"
sed
AlternativeFor longer input strings where the shell's built-in matching is inappropriate, you might also consider a perl one-liner, as described in BashFAQ #21:
in="$source" out="$solution" perl -pe 's/\Q$ENV{"in"}/$ENV{"out"}/g' <<<"$target"