Sometimes you want not just the matching lines, but the lines relative to the matches as well. For example, it could be to see the comments at start of a function block that was matched while searching a program file. Or, it could be to see extended information from a log file while searching for a particular error message.
GNU grep has three options to display lines after, before or both combined relative to matching lines.
Files used in examples are available chapter wise from learn_gnugrep_ripgrep repo. The directory for this chapter is
The sample input file for this chapter is shown below:
$ cat context.txt wheat roti bread blue toy flower sand stone light blue flower sky water dark red ruby blood evening sky rose language english hindi spanish tamil programming language python kotlin ruby
Additionally display lines after the matching lines. The number of lines required has to be specified after
If there are multiple matches, by default
grepadds a separator line
--between the results.
$ # show lines containing 'blue' and two lines after such lines $ grep -A2 'blue' context.txt blue toy flower -- light blue flower sky $ # use other options and regular expressions to refine the search $ grep -x -A2 'blue' context.txt blue toy flower
Additionally display lines before the matching lines.
$ grep -B2 'bread' context.txt wheat roti bread $ grep -B3 'ruby' context.txt sky water dark red ruby -- programming language python kotlin ruby
This option can be used instead of specifying both
-B if the count of lines required is the same. You can also use
-N instead of
$ # same as: grep -A1 -B1 'sky' context.txt $ # can also use: grep -1 'sky' context.txt $ grep -C1 'sky' context.txt flower sky water -- blood evening sky rose $ grep -A1 -B2 'sky' context.txt light blue flower sky water -- ruby blood evening sky rose
No error or warning if the count goes beyond lines available for any of these three options.
$ grep -C2 'kotlin' context.txt programming language python kotlin ruby
-- won't be added if two or more groups of matching lines have overlapping lines or are next to each other in input file.
$ # -n option used only for illustration purposes $ # prefix is : for matching lines and - for relative lines $ # group 6-8 and group 9-11 are next to each other here $ grep -n -C1 'flower' context.txt 6- toy 7: flower 8- sand stone 9-light blue 10: flower 11- sky $ # example for overlapping case (line number 9) $ # last line of 1st group overlaps with matching line of 2nd group $ grep -n -A4 'blue' context.txt 5:blue 6- toy 7- flower 8- sand stone 9:light blue 10- flower 11- sky 12- water 13-dark red
--group-separator to change the default separator
-- to something else.
$ seq 29 | grep --group-separator='*****' -A1 '3' 3 4 ***** 13 14 ***** 23 24 $ # only matching line is shown if count 0 is used with -A/-B/-C $ grep -A0 --group-separator='*-----------*-----------*' 'in' context.txt evening sky *-----------*-----------* hindi *-----------*-----------* programming language *-----------*-----------* kotlin
--no-group-separator option if the separator line is a hindrance, for example feeding the output of
grep to another program.
$ seq 29 | grep --no-group-separator -A1 '3' 3 4 13 14 23 24 $ # sum of values based on grep output $ seq 29 | grep --no-group-separator -A1 '3' | datamash sum 1 81
Context matching got its own chapter mainly due to corner cases and customization options (on Ubuntu,
man grep doesn't even list them).
a) For this question, create
exercises/context_matching directory and then save this file from learn_gnugrep_ripgrep repo as
palindrome.py. For this input file, display all lines matching
raise and one line before it.
$ # assumes 'exercises/context_matching' as CWD $ grep ##### add your solution here if re.search(r'[^a-zA-Z]', ip_str): raise ValueError("Characters other than alphabets and punctuations") elif len(ip_str) < 3: raise ValueError("Less than 3 alphabets")
b) Input has group of lines with single empty line in between. Change it to double empty lines between groups.
$ lines='rat\ndog\nbat\n\n42\n3.14\n\nhi there\nhave a nice day' $ printf '%b' "$lines" | grep ##### add your solution here rat dog bat 42 3.14 hi there have a nice day