tags:

views:

185

answers:

4

I'd like to use a sed script like this

#n
/^TODO/,/^$/p

except that sed should stop printing the range after it comes across two consecutive blank lines, rather than just one blank line. Then it should continue scanning for the next range of interest. In other words, the end of range of interest is defined by two blank lines. I'm not even sure that an address range can handle this sort of requirement, so if there's another way to do this, please let me know.

A: 

use sed for simple substitution.

$ more file
1
2
blah blah
TODO
blah blah
4
5


6
7
8
9
10


11
end
$ awk -vRS="\n\n" '/TODO/{print;exit}' file
1
2
blah blah
TODO
blah blah
4
5
ghostdog74
He said two consecutive blank lines, not the second blank line encountered. Plus your first one adds a blank line when it prints the first one (before the "4").
Dennis Williamson
A: 
sed 'N;/^\n$/q;P;D'

Proof of Concept

$ cat double_blank.txt
foo
bar

baz


blah
one
two

three

Result

$ sed 'N;/^\n$/q;P;D' double_blank.txt
foo
bar

baz


SiegeX
This fails if the lines are paired "non-blank/blank" followed by "blank/non-blank". If the second pair is "blank/blank" so there are three blank lines in a row, then it stops one line too late. So the only correct result is if the first pair of blank lines falls on odd/even lines.
Dennis Williamson
good find. code fixed.
SiegeX
+2  A: 

This should stop when it encounters two consecutive blank lines regardless of the odd/even pairing of the blank lines with non-blank lines:

Don't print the two blank lines:

sed -n 'N;/^\n$/q;P;D'

Print one of them:

sed -n 'N;/^\n$/{P;q};P;D'

Print both of them:

sed -n 'N;/^\n$/{p;q};P;D'

Edit:

And here's how you'd make that work in your range:

sed -n '/^TODO/,${N;/^\n$/q;P;D}'

Edit 2:

Per dan's (the OP) comments and edited requirements, this seems to work to find the pattern in a range that ends in two blank lines, multiple times in a file:

sed -n '/^TODO/,/^$/{H;N;/^\n$/{b};p}'
Dennis Williamson
Thanks. This one worked for me. I had trouble getting it to work as a one-liner so I had to spread it out over a few lines in a sed script. When I tried it as a one-liner, I got this error: "extra characters at the end of D command". But it did work when I put each command on its own line. Do you know why that might be?
dan
I just noticed that this script stops working after hitting the 1 double-blank-lines. Ideally, I'd want it to continue scanning the file for the next similar pattern.
dan
One thing is that different versions of `sed` behave differently. Someone had a similar error the other day. I wonder whether, instead, it has something to do with some strange Unicode thing. Did you copy and paste the command or did you type it in? If the former, try typing it by hand and see if you get the same error.
Dennis Williamson
Oh, sorry, in your question you said "stop printing".
Dennis Williamson
You're right, I should have written "stop printing that range, but continue scanning for the next one" -- I'll edit my question.
dan
Here's what I have so far: `sed -n '/^TODO/,/^$/{H;N;/^$/{p;b}};/^$/{x;p}'` - unfortunately, it skips some single blank lines and prints some more than once.
Dennis Williamson
It looks like just moving the last brace after the D command to a separate line (in a sed script file) will make it work for me.
dan
OK, it looks like it might be easier just to write a Ruby script for this.
dan
Try this: `sed -n '/^TODO/,/^$/{H;N;/^\n$/{p;b};P};/^$/{x}'`
Dennis Williamson
Or this: `sed -n '/^TODO/,/^$/{H;N;/^\n$/{b};p}'` - this seems to work, but it prints an extra line sometimes.
Dennis Williamson
That actually seems to delete every other non-blank line in the lines following /^TODO/
dan
Perfect. The last one worked
dan
A: 

Building on SiegeX's answer:

cat > lines <<'EOF'
a


c
d
EOF
sed '/^$/N; /^\n$/q' lines
Tobu
How would you make this work with the OP's range requirement?
Dennis Williamson