Reputation: 313
I'm trying to replace a single line in a file with a multiline string stored in a variable.
I am able to get the correct result when printing to screen, but not if I want to do an in-place replacement.
The file has form:
*some code*
*some code*
string_to_replace
*some code*
I want the resulting file to be:
*some code*
*some code*
line number 1
line number 2
line number 3
*some code*
The code I tried was:
new_string="line number 1\nline number 2\nline number 3"
# Correct output on screen
sed -e s/"string_to_replace"/"${new_string}"/g $file
# Single-line output in file: "line number 1line number 2line number 3"
sed -i s/"string_to_replace"/"${new_string}"/g $file
When trying to combine -i
and -e
options, the result is the same as when only using -i
.
I'm using GNU sed version 4.1.5 on CentOS (connected to it through ssh from Mac).
Upvotes: 8
Views: 21266
Reputation: 1
I don't know If you are still in need for help but I found a way using a nested sed command line to which you can provide the exact line number if you want to replace it whole in your input file with a multi-line string variable:
sed -i -e "s/$(sed -ne "3p" input)/$my_string/" input
Here, I am using the sed command expansion syntax which will return the line we want to replace (in this case, I arbitrary choose line 3 but you can adjust it as you want by replacing the number 3 in "3p" with a convenient one).
This works for me and It should work for you and everyone as well :), hopefully...
Upvotes: 0
Reputation: 189317
Inlining a multi-line string into a sed
script requires you to escape any literal newlines (and also any literal &
characters, which otherwise interpolates the string you are replacing, as well as of course any literal backslashes, and whichever character you are using as the replacement delimiter). What exactly will work also depends slightly on the precise sed
dialect. Ultimately, this may be one of those cases where using something else than sed
is more robust and portable. But try e.g.
sed -e 's/[&%\\]/\\&/g' \
-e '$!s/$/\\/' \
-e '1s/^/s%string_to_replace%/' \
-e '$s/$/%g/' <<<$replacement |
# pass to second sed instance
sed -f - "$file"
The <<<"here string"
syntax is Bash-specific; you can replace it with printf '%s\n' "$replacement" | sed
.
Not all sed
versions allow you to pass in a script on standard input with -f -
. Maybe try replacing the lone dash with /dev/stdin
or /dev/fd/0
; if that doesn't work, either, you'll have to save the generated script to a temporary file. (Bash lets you use a command substitution sed -f <(sed ...) "$file"
which can be quite convenient, and saves you from having to remove the temporary file when you are done.)
Demo: https://ideone.com/uMqqcx
Upvotes: 1
Reputation: 1521
Although you have specifically asked for sed, you can accomplish this using awk
by storing your multiline variable in a file using the following
awk '/string_to_replace/{system("cat file_with_multiple_lines");next}1' file_to_replace_in > output_file
Upvotes: 4
Reputation:
In sed
you can double quote the command string and let the shell do the expansion for you, like this:
new_string="line number 1\nline number 2\nline number 3"
sed -i "s/string_to_replace/$new_string/" file
Upvotes: 3