Actually sed -n '/pattern/{n;p}' filename
will fail if the pattern
match continuous
lines:
$ seq 15 |sed -n '/1/{n;p}'
2
11
13
15
The expected answers should be:
2
11
12
13
14
15
My solution is:
$ sed -n -r 'x;/_/{x;p;x};x;/pattern/!s/.*//;/pattern/s/.*/_/;h' filename
For example:
$ seq 15 |sed -n -r 'x;/_/{x;p;x};x;/1/!s/.*//;/1/s/.*/_/;h'
2
11
12
13
14
15
Explains:
x;
: at the beginning of each line from input, use x
command to exchange the contents in pattern space
& hold space
./_/{x;p;x};
: if pattern space
, which is the hold space
actually, contains _
(this is just a indicator
indicating if last line matched the pattern
or not), then use x
to exchange the actual content of current line
to pattern space
, use p
to print current line
, and x
to recover this operation. x
: recover the contents in pattern space
and hold space
./pattern/!s/.*//
: if current line
does NOT match pattern
, which means we should NOT print the NEXT following line, then use s/.*//
command to delete all contents in pattern space
./pattern/s/.*/_/
: if current line
matches pattern
, which means we should print the NEXT following line, then we need to set a indicator
to tell sed
to print NEXT line, so use s/.*/_/
to substitute all contents in pattern space
to a _
(the second command will use it to judge if last line matched the pattern
or not).h
: overwrite the hold space
with the contents in pattern space
; then, the content in hold space
is ^_$
which means current line
matches the pattern
, or ^$
, which means current line
does NOT match the pattern
.s/.*/_/
, the pattern space
can NOT match /pattern/
, so the s/.*//
MUST be executed!