8

I spent ages trying to figure this out. As it happens, I don't need to do it any more; I found another way. But for the sake of my sanity, I'd like to know the answer anyway.

It's quite easy to use sed to replace a marker with some piece of text. What I can't figure out is how to make sed insert a huge block of text, with complex formatting such as multiple lines, tab characters, etc. How do you do that? Is sed the best thing to use or what?

1
  • 1
    I find that python & regex are much flexible than sed in complex multi-line substitutions.
    – tombolinux
    Feb 26, 2013 at 5:04

5 Answers 5

4

I would use ex for that kind of task, unless you really do have a stream of data. I'd keep the ex commands in a here document:

ex $FILENAME << END_EX_COMMANDS
" Find the mark, assuming it's an entire line
/^MARKER$/
" Delete the marker line
d
" Add the complex, multi-line text
a
Complex, vividly formatted text here.
Even more "specially" formatted text.
.
" The '.' terminates the a-command. Write out changed file.
w!
q
END_EX_COMMANDS

Using ex is an advantage to vi or vim users: they already know the keystrokes for the commands, although it gives you the sensation of editing blind. You can also do multiple adds or global substitutions, anything that vim can do in ':' mode.

3

If you have the text to be inserted at the marker(s) in a file named /tmp/insert.txt you can accomplish this task as follow:

sed '/MARKER/ r /tmp/insert.txt' < inputfile

The above sed command will read "inputfile" and look for MARKER. When it finds it, it inserts the contents of /tmp/insert.txt into the output stream.

If you want the marker itself to be deleted, try this:

sed '/MARKER/ {s/MARKER//; r /tmp/insert.txt
}' <inputfile

Note the "}" closing brace must be preceded by a new line.

As in the first command, the sed will operate on lines with the MARKER. It will substitute MARKER with nothing, and then it will read in /tmp/insert.txt

2

I believe this command is what you are looking for:

r FILENAME
     As a GNU extension, this command accepts two addresses.

     Queue the contents of FILENAME to be read and inserted into the
     output stream at the end of the current cycle, or when the next
     input line is read.  Note that if FILENAME cannot be read, it is
     treated as if it were an empty file, without any error indication.

     As a GNU `sed' extension, the special value `/dev/stdin' is
     supported for the file name, which reads the contents of the
     standard input.
0

Here is a simplified version of Bruce Ediger's answer using change command which is a combination of delete and append.

ex $FILENAME << EOEX
/^MARKER$/c
The new text
to be inserted
here.
.
w!
q
EOEX
0

If you want the marker itself to be deleted, try this in one line:

sed -e '/MARKER/ r /tmp/insert.txt' -e '/MARKER/d' < inputfile

or

sed -e '/MARKER/ {r /tmp/insert.txt' -e 'd }' < inputfile

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .