Replace line with multi-line file

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).



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



FILE=`cat replace.txt`

sed -i "3s/.*/$(echo "${FILE}")/" tmp.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)?

3 answers

  • answered 2018-03-13 21:44 Socowi

    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


    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".

  • answered 2018-03-13 22:01 karakfa

    sed can do this with some quote juggling

    $ seq 5 | sed -e '/3/{r replace.txt' -e 'd}'
      apple size=8, align=2, ..., etc.
      banana size=64, align=8, ..., etc.
      carrot size=92, align=4, ..., etc.

    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.

  • answered 2018-03-13 22:12 William Pursell

    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.