10

This question already has an answer here:

How can I print all the lines between two lines starting with one pattern for the first line and ending with another pattern for the last line?


Update
I guess it was a mistake to mention that this document is HTML. I seem to have touched a nerve, so forget that. I'm not trying to parse HTML or do anything with it other than print a section of a text document.


Consider this example:

aaa
bbb
pattern1
aaa pattern2
bbb
ccc
pattern2
ddd
eee
pattern1
fff
ggg

Now, I want to print everything between the first instance of pattern1 starting at the beginning of a line and pattern2 starting at the beginning of another line. I want to include the pattern1 and pattern2 lines in my output, but I don't want anything after the pattern2 line.

pattern2 is found in one of the lines of the section. I don't want to stop there, but that's easily remedied by indicating the start of the line with ^.

pattern1 appears on another line after pattern2, but I don't want to look at that at all. I'm just looking for everything between the first instance of pattern1 and the first instance of pattern2, inclusive.

I found something that almost gets me there using sed:

sed -n '/^pattern1/,/^pattern2/p' inputfile.txt

... but that starts printing again at the next instance of pattern1

I can think of a method using grep -n ... | cut -f1 -d: twice to get the two line numbers then tail and head to get the section I want, but I'm hoping for a cleaner way. Maybe awk is a better tool for this task?

When I get this working, I hope to tie this into a git hook. I don't know how to do that yet, either, but I'm still reading and searching :)

Thank you.

marked as duplicate by don_crissti, Jeff Schaller, Stephen Kitt, dr01, Archemar Feb 22 '16 at 13:15

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    use a HTML parser.. – heemayl Feb 22 '16 at 7:42
  • @heemayl Is there a particular HTML parser you recommend? How do I do this from the command line? Is there something available on Unix & Linux that you can recommend? Even if there is, I'd probably prefer to do something with the tools already available on the Linux platform. – Vince Feb 22 '16 at 7:54
  • Check why stackoverflow.com/q/1732348/3789550 – heemayl Feb 22 '16 at 7:55
  • 1
    Though for general HTML an HTML parser is the way to go, if you have a particular HTML document in which the format obeys certain rules, you can avoid HTML parsers and use regular expressions. I think in this case the question is whether you need to do something about the minified parts or whether it's OK to print them as-is. Also, if you are certain that the patterns you want don't match anywhere else in the text. – RealSkeptic Feb 22 '16 at 7:57
  • You guys saw "HTML" and went crazy. This doesn't have anything to do with parsing HTML, so I updated my question. – Vince Feb 22 '16 at 8:57
13

You can make sed quit at a pattern with sed '/pattern/q', so you just need your matches and then quit at the second pattern match:

sed -n '/^pattern1/,/^pattern2/p;/^pattern2/q'

That way only the first block will be shown.

  • Excellent! That's exactly what I was looking for. And, wouldn't you know, it works just as well on an HTML file despite the knee-jerk reaction of some commenters to the original version of my question :) Thank you. – Vince Feb 22 '16 at 9:15
  • @Vince Well, the infuriated discussion makes me believe there is good reason for mentioning the dangers of HTML and regex. I cannot comment on this as I never work on HTML. – Fiximan Feb 22 '16 at 10:22
6

As a general approach, with sed, it's easy to print lines from one match to another inclusively:

$ seq 1 100 > test
$ sed -n '/^12$/,/^15$/p' test
12
13
14
15

With awk, you can do the same thing like this:

$ awk '/^12$/{flag=1}/^15$/{print;flag=0}flag' test
12
13
14
15

You can make these non-inclusive like this:

$ awk '/^12$/{flag=1;next}/^15$/{flag=0}flag' test
13
14

$ sed -n '/^12$/,/^15$/p' test | sed '1d;$d'
13
14
  • That's close, but using your example the problem in my case is that 12 appears on another line after 15 and these all start processing again after it gets to the second 12. – Vince Feb 22 '16 at 9:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.