Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use grep to print only the context

Tags:

grep

bash

shell

awk

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
like image 547
szaman Avatar asked Jul 07 '16 11:07

szaman


2 Answers

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!

like image 124
Inian Avatar answered Sep 20 '22 14:09

Inian


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.

like image 21
Anthony Geoghegan Avatar answered Sep 22 '22 14:09

Anthony Geoghegan