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?
Asked
Active
Viewed 5.9k times
40
-
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 Answers
37
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
- 47,994
- 12
- 82
- 119
-
2hey 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
-
1If 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
9
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,849
- 5
- 37
- 46
-
1This only works for the first match, any subsequent matches will be thrown away. – Chris Eberle Jun 08 '11 at 15:43
-
I added a second way to to it - this time it also works with more than one match. – bmk Jun 08 '11 at 16:04
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
- 86,532
- 28
- 194
- 218
-
8That doesn't meet the requirement though - it shows all the intermediate lines as well. – Cybergibbons Jun 11 '15 at 10:25
6
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
- 805
- 9
- 14