34

I've seen some examples of grepping lines before and after, but I'd like to ignore the middle lines. So, I'd like the line five lines before, but nothing else. Can this be done?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
mike628
  • 36,755
  • 16
  • 37
  • 51
  • Question is not clear, is it line 5 before match, or the 5 lines before match – CharlesB Jun 08 '11 at 16:14
  • Dup of http://stackoverflow.com/questions/9081/grep-a-file-but-show-several-surrounding-lines – Vadzim Jul 15 '14 at 13:33
  • This comment is coming way late, but ask yourself: once you have identified the "reference line" and the five previous with `grep -B5 "foo" file`, is there something diagnostic about that line other than that it is 5 lines before? For example, are you looking for a particular error, and wanting to return the process id? Then maybe `grep -B5 "foo" file | grep "bar"` might be the easiest thing. – Chris Cox Jan 19 '16 at 01:13

4 Answers4

34

OK, I think this will do what you're looking for. It will look for a pattern, and extract the 5th line before each match.

grep -B5 "pattern" filename | awk -F '\n' 'ln ~ /^$/ { ln = "matched"; print $1 } $1 ~ /^--$/ { ln = "" }'

basically how this works is it takes the first line, prints it, and then waits until it sees ^--$ (the match separator used by grep), and starts again.

Chris Eberle
  • 44,989
  • 12
  • 77
  • 112
  • 2
    hey Chris, Not an awk user, but I'd like to understand this a little better. Can you explain the awk part,in detail.I looked at a bunch on tutorials online and some of this I couldn't figure out. – mike628 Jun 09 '11 at 13:09
  • 1
    If I were going to solve this with awk, it might be more straight-forward to do `grep -B5 "pattern" filename | awk '{mod=NR%7; if (mod==1) {print $0}}'`. 7 because 1 matching row + 5 context rows + 1 separator row. The first row of output will be a separator row, so the row of interest will be every 7th row, starting with the second. NR is a zero-based row number that awk gives you automatically. – Chris Cox Jan 19 '16 at 01:32
  • Thx for `-B`. I was missing it so much. Also `-An` that means "show n lines after" is possible – vladkras Jun 28 '17 at 08:21
8

If you only want to have the 5th line before the match you can do this:

grep -B 5 pattern file | head -1

Edit:
If you can have more than one match, you could try this (exchange pattern with your actual pattern):

sed -n '/pattern/!{H;x;s/^.*\n\(.*\n.*\n.*\n.*\n.*\)$/\1/;x};/pattern/{x;s/^\([^\n]*\).*$/\1/;p}' file

I took this from a Sed tutorial, section: Keeping more than one line in the hold buffer, example 2 and adapted it a bit.

bmk
  • 13,031
  • 5
  • 34
  • 40
7

This is option -B

   -B NUM, --before-context=NUM
    Print  NUM  lines  of  leading  context  before  matching lines.
    Places  a  line  containing  --  between  contiguous  groups  of
    matches.
CharlesB
  • 75,315
  • 26
  • 174
  • 199
4

This way is easier for me:

grep --no-group-separator -B5 "pattern" file | sed -n 1~5p

This greps 5 lines before and including the pattern, turns off the --- group separator, then prints every 5th line.

harleygolfguy
  • 675
  • 7
  • 12