Sign up ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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

share|improve this question
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. – Gilles Quenot Oct 8 '12 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. – Nathan Long Oct 8 '12 at 17:06
Nevermind, that will works, I will edit my POST accordingly. – Gilles Quenot Oct 8 '12 at 17:10

6 Answers 6

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


pcregrep -M "Foo\nBar" file


share|improve this answer
The OP didn't say that Foo and Bar would comprise the entire line. – tojrobinson Oct 8 '12 at 15:46

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.

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

@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' .
share|improve this answer
So accept warl0cks answer. – Nils Oct 11 '12 at 20:35

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. have really good stuff about shell programming.

share|improve this answer
What does h, n, H, x, p, q means? Very interesting. – Yamaneko Oct 8 '12 at 16:40
See my comments. More infos on pattern space & hold space : or in french – Gilles Quenot Oct 8 '12 at 16:43
POST adapted to work on a directory – Gilles Quenot Oct 8 '12 at 17:12

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)

share|improve this answer

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
share|improve this answer
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 '12 at 8:19
Good point, thanks – bbaja42 Oct 9 '12 at 8:54

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.