Only cat from specific line X (with a pattern) to other specific line Y (with a pattern)

awkgrepheadsedtail

A little extended problem from "cat line x to line y on a huge file":

I have a huge file (2-3 GB). I'd like to cat/print only from the line having "foo:" to the line having "goo:". Assume that "foo:" and "goo:" only appear once in a file; "foo:" proceeds "goo:".

So far this is my approach:

  • First, find the line with "foo:" and "goo:": grep -nr "foo:" bigfile
  • Returns 123456: foo: hello world! and 654321: goo: good bye!
  • Once I know these starting and ending line numbers, and the difference (654321-123456=530865) I can do selective cat:
  • tail -n+123456 bigfile | head -n 530865

My question is that how can I effectively substitute the line number constants with expressions (e.g., grep …)?

I can write a simple Python script but want to achieve it using only combining commands.

Best Answer

sed -n '/foo/,/goo/p;/goo/q' <bigfile

That would print only those lines. If you wanted the line numbers you'd add an =.

sed -n '/foo/=;/goo/=;//q' <bigfile

The q is important because it quits the input when it is called - else sed will continue to read the infile through to the end.

If you don't want to print foo/goo lines you can do instead:

With GNU sed:

sed -n '/foo/,/goo/!d;//!p;/goo/q
' <<\DATA
line1
foo 
line3
line4
line5
goo 
line7
DATA

OUTPUT

line3
line4
line5

And with any other:

sed -n '/foo/G;/\n/,/goo/!d;//q;/\n/!p 
' <<\DATA
line1
foo 
line3
line4
line5
goo 
line7
DATA    

OUTPUT

line3
line4
line5

Either way, though, this also quits its input as soon as it encounters the last line in your search.

Related Question