Reputation: 868
Trying to replace a line with a multi-line file. I can easily do this with a single-line file or multi-line string (see below).
#!/bin/bash
NEW_STRING="apple\nbanana\ncarrot"
sed -i "3s/.*/$(echo "${NEW_STRING}")/" tmp.txt
# Outputs...
# line 1
# line 2
# apple
# banana
# carrot
# line 4
# line 5
# ...
# etc
However, when I change the code to use a multi-file, such as replace.txt
, I receive the following error:
sed: -e expression #1, char 10: unterminated `s' command
broken_script.bash
#!/bin/bash
FILE=`cat replace.txt`
sed -i "3s/.*/$(echo "${FILE}")/" tmp.txt
replace.txt
++++
++++++++++++++++++++++++++++++++++++++++++++++
apple size=8, align=2, ..., etc.
banana size=64, align=8, ..., etc.
...
carrot size=92, align=4, ..., etc.
Note broken_script.bash
works if I delete replace.txt
to be a single-line (i.e. just ++++
).
Does anyone see what I'm doing wrong? Why doesn't this work with a multi-line file as the replacement text (i.e. like the single-line file or multi-line string)?
Upvotes: 0
Views: 178
Reputation: 212198
To replace lines with the contents of a file, you can use the r
command:
sed -e 3rreplace.txt -e 3d tmp.txt
As asked in a comment, sed -e 3d -e 3rreplace.txt
does not work because the d
command immediately returns to the top of the program after reading the next line and never executes the r
command.
Upvotes: 2
Reputation: 67467
sed
can do this with some quote juggling
$ seq 5 | sed -e '/3/{r replace.txt' -e 'd}'
1
2
++++
++++++++++++++++++++++++++++++++++++++++++++++
apple size=8, align=2, ..., etc.
banana size=64, align=8, ..., etc.
...
carrot size=92, align=4, ..., etc.
4
5
for in place replacement you need to provide file
$ sed -i -e '/3/{r replace.txt' -e 'd}' file
of course test first or take backup.
Upvotes: 1
Reputation: 27195
First of all: Drop the echo
part. You can use the variable directly.
Back to the actual problem:
The difference is how you encode the newline. In the first command you wrote \n
do denote a newline. That \n
is not interpreted by 'bash', but directly sent to sed
. In the second command, the file content is sent to sed
, including literal newline characters. For a file with the two lines line1
and line2
the command sed
sees is
3s/.*/line1
line2/
sed
cannot handle such multi-lined commands.
Non-sed solution:
As it seems, you just want to replace the third line of one file with the content of another file. This can be done with
cat <(head -n 2 file1) file2 <(tail -n +4 file1)
head -n2 file1
prints the first two lines of file1
.
tail -n +4 file 1
prints all lines of file1
starting at line 4.
<(command)
is called process substitution and emulates a file containing the output of command
.
cat
concatenates the three "files".
Upvotes: 1