Context matching
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 the 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 the matching lines. And there are a couple of options to customize the separator between matching groups.
The example_files directory has all the files used in the examples.
The sample input file used in 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
-A
Helps to get lines after the matching lines. The number of lines required has to be specified after the -A
option.
# match whole line 'blue' and also display two lines after such lines
$ grep -x -A2 'blue' context.txt
blue
toy
flower
If there are multiple matches, grep
adds a separator line --
between the groups.
# show lines containing 'blue' and two lines after such lines
$ grep -A2 'blue' context.txt
blue
toy
flower
--
light blue
flower
sky
-B
Helps to get 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
Here's an example with both -A
and -B
options:
$ grep -A1 -B2 'sky' context.txt
light blue
flower
sky
water
--
ruby
blood
evening sky
rose
-C
This option can be used instead of specifying both -A
and -B
if the number of lines required is the same. You can also use -N
instead of -CN
.
# 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
You'll not get any error or warning if the count goes beyond the number of lines available for any of these options.
$ grep -C2 'kotlin' context.txt programming language python kotlin ruby
Contiguous matches
The separator --
won't be added if two or more groups of matching lines have overlapping lines or are next to each other in the input file.
Here's an example when the groups are next to each other:
# -n option is used here for illustration purposes
# separator 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
And here's an example for groups with common lines between them:
# relative line of 1st group (line 9) 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
Customizing separators
Use --group-separator
to change the default separator --
to something else.
$ seq 29 | grep --group-separator='*****' -A1 '3'
3
4
*****
13
14
*****
23
24
# there are no relative lines if the context count is 0
$ grep -A0 --group-separator='*-----------*-----------*' 'in' context.txt
evening sky
*-----------*-----------*
hindi
*-----------*-----------*
programming language
*-----------*-----------*
kotlin
Use the --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
# passing the grep output to another program
$ seq 29 | grep --no-group-separator -A1 '3' | datamash sum 1
81
Summary
This chapter showed how you can display lines relative to the matching ones. You also learned how to customize group separators.
Exercises
The exercises directory has all the files used in this section.
1) For the input file sample.txt
, filter lines containing do
and also display the line that comes after such a matching line.
##### add your solution here
Just do-it
Believe it
--
Much ado about nothing
He he he
2) For the input file sample.txt
, filter lines containing o
followed by zero or more characters and then m
or r
. Also, display the line that comes before such a matching line.
##### add your solution here
Hello World
--
Hi there
How are you
--
He he he
Adios amigo
3) Will you get an error if there are no lines to satisfy the context specified? For example, Hello
matches only the first line of the sample.txt
file. If you try grep -B5 'Hello' sample.txt
will you get the first line in the output or an error?
4) For the input file sample.txt
, filter lines containing pay
and also display the line that comes before and after such a matching line.
##### add your solution here
banana
papaya
mango
5) For the input file sample.txt
, filter lines containing lie
and also display the line that comes before and two lines after such a matching line.
##### add your solution here
Just do-it
Believe it
banana
6) Will the -v
option work as expected when combined with the context based options?
7) Under what conditions will the separator --
be absent even when there are multiple context matches?
8) For the input file sample.txt
, filter lines containing are
or he
as whole words as well as the line that comes before such a matching line. There should be no separator between the groups of matching lines in the output.
##### add your solution here
Hi there
How are you
Much ado about nothing
He he he
9) For the input file sample.txt
, filter lines containing pay
or the
as well as the line that comes after/before such a matching line. Show =====
as the separator between the groups of matching lines in the output.
##### add your solution here
Hi there
How are you
=====
banana
papaya
mango
10) The input file sample.txt
has an empty line between group of lines. Change it to double empty lines between the groups.
##### add your solution here
Hello World
Hi there
How are you
Just do-it
Believe it
banana
papaya
mango
Much ado about nothing
He he he
Adios amigo