Reputation: 103714
Suppose I have a file with:
Line 1
Line 2
Start Line 3
Line 4
Line 5
Line 6
End Line 7
Line 8
Line 9
Start Line 10
Line 11
End Line 12
Line 13
Start line 14
Line 15
I want to use sed
to print between the patterns only if both /Start/
and /End/
are found.
sed -n '/Start/,/End/p'
works as expected if you know both markers are there and in the order expected, but it just prints from Start
to the end of the file if End
is either out of order or not present. (i.e., prints line 14 and line 15 in the example)
I have tried:
sed -n '/Start/,/End/{H;}; /End/{x; p;}' file
Prints:
# blank line here...
Start Line 3
Line 4
Line 5
Line 6
End Line 7
End Line 7
Start Line 10
Line 11
End Line 12
which is close but two issues:
I am hoping for a result similar to
$ awk '/Start/{x=1} x{buf=buf$0"\n"} /End/{print buf; buf=""; x=0}' file
Start Line 3
Line 4
Line 5
Line 6
End Line 7
Start Line 10
Line 11
End Line 12
(blank lines between the blocks not necessary...)
Upvotes: 2
Views: 128
Reputation: 784918
You can use this awk:
awk 'x{buf=buf ORS $0} /Start/{x=1; buf=$0} /End/{print buf; buf=""; x=0}' file
Start Line 3
Line 4
Line 5
Line 6
End Line 7
Start Line 10
Line 11
End Line 12
Here is a sed
version to do the same on OSX (BSD) sed
(Based on Benjamin's sed command):
sed -n -e '/Start/{:a;' -e 'N;/End/!ba;' -e 'p;}' file
Upvotes: 1
Reputation: 88553
With GNU sed and sed from Solaris 11:
sed -n '/Start/{h;b;};H;/End/{g;p;}' file
Output:
Start Line 3 Line 4 Line 5 Line 6 End Line 7 Start Line 10 Line 11 End Line 12
If Start
is found copy current pattern space to hold space (h
) and branch to end of script (b
). For every other line append current pattern space to hold space (H
). If End
is found copy hold space back to pattern space (g
) and then print pattern space (p
).
Upvotes: 2
Reputation: 52112
GNU sed: after encountering Start
, keep appending lines as long as we don't see End
; once we do, print the pattern space and start over:
$ sed -n '/Start/{:a;N;/End/!ba;p}' infile
Start Line 3
Line 4
Line 5
Line 6
End Line 7
Start Line 10
Line 11
End Line 12
Getting the newline between blocks is tricky. This would add one after each block, but results in an extra blank at the end:
$ sed -n '/Start/{:a;N;/End/!ba;s/$/\n/p}' infile
Start Line 3
Line 4
Line 5
Line 6
End Line 7
Start Line 10
Line 11
End Line 12
[blank]
Upvotes: 1
Reputation: 212198
Personally, I prefer your awk solution, but:
sed -n -e '/start/,/end/H' -e '/end/{s/.*//; x; p}' input
Upvotes: 0