7

Using grep, you can print lines that match your search query. Adding a -C option will print two lines of surrounding context, like this:

> grep -C 2 'lorem'
some context
some other context
**lorem ipsum**
another line
yet another line

Similarly, you can use grep -B 2 or grep -A 2 to print matching lines with two preceding or two following lines, respectively, for example:

> grep -A 2 'lorem'
**lorem ipsum**
another line
yet another line

Is it possible to skip the matching line and only print the context? Specifically, I would like to only print the line that is exactly 2 lines above a match, like this:

> <some magic command>
some context
Inian
  • 71,145
  • 9
  • 121
  • 139
szaman
  • 1,681
  • 1
  • 13
  • 25

3 Answers3

4

If you can allow couple of grep instances to be used, you can try like as I mentioned in the comments section.

$ grep -v "lorem" < <(grep -A2 "lorem" file)
another line
yet another line

$ grep -A2 "lorem" file | grep -v "lorem"
another line
yet another line

If you are interested in a dose of awk, there is a cool way to do it as

$ awk -v count=2 '{a[++i]=$0;}/lorem/{for(j=NR-count;j<NR;j++)print a[j];}' file
another line
yet another line

It works by storing the entire file in its own array and after searching for the pattern lorem, the awk special variable which stores the row number(NR), points at the exact line in which the pattern is found. If we loop for 2 lines before it as dictated by the awk variable -v count, we can print the lines needed.

If you are interested in the printing the pattern also, just change the condition in for-loop as j<=NR instead of j<NR. That's it!

Inian
  • 71,145
  • 9
  • 121
  • 139
1

There’s no way to do this purely through a grep command. If there’s only one instance of lorem in the text, you could pipe the output through head.

grep -B2 lorem t | head -1

If there may be multiple occurrence of lorem, you could use awk:

awk '{second_previous=previous; previous=current_line; current_line=$0}; /lorem/ { print second_previous; }'

This awk command saves each line (along with the previous and the one before that) in variables so when it encounters a line containing lorem, it prints the second last line. If lorem happens to occur in the first or second line of the input, nothing would be printed.

Anthony Geoghegan
  • 10,874
  • 5
  • 46
  • 55
1

awk, as others have said, is your friend here. You don't need complex loops or arrays or other junk, though; basic patterns suffice.

When you use -B N, (and the --no-group-separator flag) you get output in groups of M=N+1 lines. To select precisely one of those lines (in your question, you want the very first of the group), you can use modular arithmetic (tested with GNU awk).

awk -vm=3 -vx=1 'NR%m==x{print}'

You can think of the lines being numbered like this: they count up until you reach the match, at which point they go back to zero. So set m to N+1 and x to the line you want to extract.

1 some context
2 some other context
0 **lorem ipsum**

So the final command would be

grep -B2 --no-group-separator lorem $input | awk -vm=3 -vx=1 'NR%m==x{print}'
wirefox
  • 434
  • 12
  • 14