7

I would like to search for a certain pattern (say Bar line) but also print lines above and below (i.e 1 line) the pattern or 2 lines above and below the pattern.

Foo  line
Bar line
Baz line

....

Foo1 line
Bar line
Baz1 line

....
Rpj
  • 3,526
  • 12
  • 36
  • 80
  • Possible duplicate of [Grep a file, but show several surrounding lines?](http://stackoverflow.com/questions/9081/grep-a-file-but-show-several-surrounding-lines) – phuclv Jan 05 '17 at 08:54

2 Answers2

15

Use grep with the parameters -A and -B to indicate the number a of lines After and Before you want to print around your pattern:

grep -A1 -B1 yourpattern file
  • An stands for n lines "after" the match.
  • Bm stands for m lines "before" the match.

If both numbers are the same, just use -C:

grep -C1 yourpattern file

Test

$ cat file
Foo  line
Bar line
Baz line
hello
bye
hello
Foo1 line
Bar line
Baz1 line

Let's grep:

$ grep -A1 -B1 Bar file
Foo  line
Bar line
Baz line
--
Foo1 line
Bar line
Baz1 line

To get rid of the group separator, you can use --no-group-separator:

$ grep --no-group-separator -A1 -B1 Bar file
Foo  line
Bar line
Baz line
Foo1 line
Bar line
Baz1 line

From man grep:

   -A NUM, --after-context=NUM
          Print NUM  lines  of  trailing  context  after  matching  lines.
          Places   a  line  containing  a  group  separator  (--)  between
          contiguous groups of matches.  With the  -o  or  --only-matching
          option, this has no effect and a warning is given.

   -B NUM, --before-context=NUM
          Print  NUM  lines  of  leading  context  before  matching lines.
          Places  a  line  containing  a  group  separator  (--)   between
          contiguous  groups  of  matches.  With the -o or --only-matching
          option, this has no effect and a warning is given.

   -C NUM, -NUM, --context=NUM
          Print NUM lines of output context.  Places a line  containing  a
          group separator (--) between contiguous groups of matches.  With
          the -o or --only-matching option,  this  has  no  effect  and  a
          warning is given.
fedorqui 'SO stop harming'
  • 228,878
  • 81
  • 465
  • 523
3

grepis the tool for you, but it can be done with awk

awk '{a[NR]=$0} $0~s {f=NR} END {for (i=f-B;i<=f+A;i++) print a[i]}' B=1 A=2 s="Bar" file

NB this will also find one hit.

or with grep

grep -A2 -B1 "Bar" file
Jotne
  • 38,154
  • 10
  • 46
  • 52
  • @Jonte Could you explain your command? Also is it possible to do this for multiple hits rather than just one? – user1692342 Sep 21 '17 at 01:59
  • @user1692342 awk store all lines in an array named `a`, then it start printing out lines if it match the `B` before and `A` after hits. Yes awk can handle multiple hits, but may become rather complex. – Jotne Sep 27 '17 at 07:21