There are a few ways to go about this w/ sed
. One way is a delayed read as is recommended in the accepted answer. It could also be written like:
sed -e '$!N;P;/\nPointer/r file1' -e D file2
...with a little explicit look-ahead instead of the look-behind implemented elsewhere with the hold buffer. That will inevitably have the same problem with the last line that @don_crissti notes, though, because N
does increment the line cycle and the r
ead command is applied by line number.
You can get around it:
echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -
Not all sed
s will interpret the -
to mean standard input, but many do. (POSIX says sed
should support -
to mean standard-in if the implementer wants -
to mean standard-in???)
Another way is to handle the appended content in order. There is another command that schedules output in the same way r
ead does, and sed
will apply it and r
ead in the order they're scripted. It's a little more involved though - it entails using one sed
to a
ppend the Pointer
match to the output of another sed
in its script.
sed ' /Pointer/!d #only operate on first match
s/[]^$&\./*[]/\\&/g;H #escape all metachars, Hold
s|.*|/&/!p;//!d|p;g #print commands, exchange
s|.|r file1&a\\&|;q' file2| #more commands, quit
sed -nf - file2 #same input file
So basically the first sed
writes the second sed
a script, which the second sed
reads on standard-input (maybe...) and applies in turn. The first sed
only works on the first match for Pointer
found, and afterward q
uits input. Its job is to...
s/[]^$&\./*[]/\\&/g;H
- Make sure that all pattern chars are safely backslash-escaped because the second
sed
is going to need to interpret every bit it reads literally to get it right. Once that's done, put a copy in H
old space.
s|.*|/&/!p;//!d|p; x
- Tell the second
sed
to p
rint every input line !
but the /&/
one we just pattern-safed; and then to d
elete all of the same. p
rint the commands at the second sed
, then ex
change the h
old and pattern buffers to work on our saved copy.
s|.|r file1&a\\&|p;q
- The only char we work with here is a
\n
ewline because sed
will have prepended one when we H
eld the line before. So we insert the command r file1
and follow it with our \n
ewline then the command a\\
for a
ppend followed also by a \n
ewline. All of the rest of our H
eld line follows that last \n
ewline.
The script that the first writes looks something like this:
/Pointer-file2 "23"/!p;//!d
r file1
a\
Pointer-file2 "23"
Basically the second sed
will print every line but the one the first sed
sets it up to a
ppend. For that particular line two delayed writes to standard-out are scheduled - the first is the r
ead of file1
and the second is a copy of the line we want after it. The first sed
's doctoring isn't even necessary in this case (see? no backslashes) but it is important to safely escape in the way I do here whenever a pattern match is repurposed as input.
Anyway, so... there are a few ways.