How can I grep a directory for lines that contain "Foo", but only get matches when the next line also contains "Bar"?

  • The problem is now totally different than the original :/ Maybe better to revert the old versions & POST another one ? Moreover the new question is not clear for me. Oct 8, 2012 at 17:03
  • @sputnick - how so? I specified a directory when I first posted the question; I only bolded it because people weren't noticing. Oct 8, 2012 at 17:06
  • Nevermind, that will works, I will edit my POST accordingly. Oct 8, 2012 at 17:10

6 Answers 6


@warl0ck pointed me in the right direction with pcregrep, but I said "contains", not "is", and I asked about a directory, not a file.

This seems to work for me.

pcregrep -rMi 'Foo(.*)\n(.*)Bar' .

Grep itself doesn't seem to support it, use pcregrep instead:


pcregrep -M "Foo\nBar" file


  • 3
    The OP didn't say that Foo and Bar would comprise the entire line. Oct 8, 2012 at 15:46

With a sed script :

#!/bin/sed -nf

    h         # put the matching line in the hold buffer
    n         # going to nextline
    /^Bar/{   # matching pattern in newline
        H     # add the line to the hold buffer
        x     # return the entire paragraph into the pattern space
        p     # print the pattern space
        q     # quit the script now

To use it :

chmod +x script.sed
printf '%s\n' * | ./script.sed

The printf here display all files in the current directory on one line each, and pass it to sed.

Note : this is sorted by alphabetical order.

More infos of useful pattern space and hold space HERE.

grymoire.com have really good stuff about shell programming.


Using grep only, you could construct the following pipe:

grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'

The first grep will get all the lines that contain Foo as well as the line after the match. Then we get lines that contain Bar as well as the line before the match, and finally extract the lines from this output that contain Foo.

EDIT: As manatwork pointed out, there are some problematic cases to be observant of. Although an interesting challenge, due to grep's line oriented functionality, any solution with it is likely to be a 'hack' and you are probably better off using something like pcregrep which is more suited to the task at hand.

  • Nice. I asked about a directory though; this seems to work: find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar' Oct 8, 2012 at 16:07
  • That will also list occurrences with both “Foo” and “Bar” on the same line.
    – manatwork
    Oct 8, 2012 at 16:12
  • @manatwork: Lines that contain "Foo" and "Bar" are "lines that contain 'Foo'" which is was what was asked. Oct 8, 2012 at 16:15
  • 1
    @tojrobinson, what about the “but only get matches when the next line also contains "Bar"” part? pastebin.com/Yj8aeCEA
    – manatwork
    Oct 8, 2012 at 16:28

While I prefer Nathan's solution using pcregrep, here is solution using only grep

grep -o -z -P  'Foo(.*)\n(.*)Bar' file

Options explanation:

  • -o print only matched part. Necessary since inclusion of -z will printout the whole file (unless there is a \0 somewhere)
  • -z Treat the input as a set of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline.
  • -P perl regex syntax

EDIT : This version prints out entire matched lines

    grep -o -P -z  '(.*)Foo(.*)\n(.*)Bar(.*)' file
  • 1
    Cool trick what -z. Some “(.*)” before and after the whole expression would make it output the entire matched lines. For now substrings before “Foo” and after “Bar” are not displayed.
    – manatwork
    Oct 9, 2012 at 8:19

With awk:

awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
     /foo/ {prev=$0; next}
     {prev=""}' file1...

(general note about awk limitation: beware that if some file names may contain "=" characters, you'll need to pass them as ./filename instead of filename to awk)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .