sed '$!N;/^\[second/,/^\n\[/P;D' <infile >outfile
That should probably do, though I'm not perfectly clear about what you want to do with the trailing blank line that immediately precedes the next section. This output includes it, because it seems the right thing to do, but if you want to drop only that one last blank line from any section that can be done relatively easily - so just ask.
Basically, for every input line which is !
not the $
last, sed
also pulls in the N
ext line and appends it to pattern space following an inserted \n
ewline character delimiter. Each time this happens the pattern space shifts:
^Line1\nLine2$
^Line2\nLine3$
^Line3\nLine4$
If the current pattern space matches the patterns ^\[second
or ^\n\[
or any line which occurs between those two, sed
will P
rint up to the first occurring \n
ewline in pattern space - and so it only prints half of its buffer for each iteration.
Last, sed
D
eletes up to the first occurring \n
ewline in pattern space and starts the script again from the top - which is how we get the shifting effect. This is known as a sliding window. It works very well, and is quite fast.
I guess there are multiple versions of this question or something? Whatever the case, going the opposite way is not so difficult to do, really.
You might do it like...
sed -ne '/^\[[^s]/,/^\[s/p' <in >out
Which would just print any content which doesn't follow a header beginning with an s
character, and and all headers regardless. It doesn't do the neat little newline after, though:
[first attempt]
a=10
b=20
[second attempt]
[third attempt ]
a=30
b=50
If you want to get a little more explicit you can do that too:
sed '/^\[[second]/P;$!N;//,/\n$/!P;D' <in >out
...which does do the neat little newline...
[first attempt]
a=10
b=20
[second attempt]
[third attempt ]
a=30
b=50
All of these are sed
ranges, and for each match expression that looks like:
/match1/,/match2/command
...sed
will apply the command
to both matched lines and all lines that come between.