Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am using a command like this to find files with the word 'term' in them:

grep -l term *

But I now want to be able to find files which have two different words in them (let's call them termA and termB) - not necessarily on the same line. I want to find files with both terms in, not just files that have either term.

Now I could write a cumbersome bash script for this, but does grep, egrep, awk, sed or anything else have a tool that can help me?

Thanks in advance.

share|improve this question
up vote 4 down vote accepted

If your files contain no null bytes

In this case, you can use grep alone:

grep -Plz "termA.*termB|termB.*termA" *

How it works:

  • The Perl Compatible Regular Expressions termA.*termB and termB.*termA search for strings which have both terms in it.

  • The combined PCRE termA.*termB|termB.*termA matches all strings containing both terms.

  • Finally, the -z switch makes data lines end in null bytes instead of newlines.

By the way, there's no need to use -P. If you prefer to continue using POSIX Basic Regular Expressions, the syntax is similar:

grep -lz "termA.*termB\|termB.*termA" *

If your files contain null bytes

In this case, you'll need auxiliary tools:

(grep -l termA * ; grep -l termB *) | sort | uniq -d

How it works:

  • grep -l termA * ; grep -l termB * displays all files containing either of the terms. Files that contain both terms will be displayed twice.

  • sort sorts the output.

  • uniq -d only displays duplicate lines (required lines to be sorted).

share|improve this answer
    
Thanks - this is looking for the terms to be on the same line though. – Peter Howe Jul 11 '12 at 13:25
    
Sorry, I overlooked that requirement. I've updated my answer. – Dennis Jul 11 '12 at 13:42
    
Tnanks Dennis. The uniq -d was what I needed. – Peter Howe Jul 11 '12 at 14:51

You can use either the -e or -f options to search for multiple expressions (from man grep):

    -e PATTERN, --regexp=PATTERN
          Use  PATTERN  as  the  pattern.   This  can  be  used to specify
          multiple search patterns, or to protect a pattern beginning with
          a hyphen (-).  (-e is specified by POSIX.)

   -f FILE, --file=FILE
          Obtain  patterns  from  FILE,  one  per  line.   The  empty file
          contains zero patterns, and therefore matches nothing.   (-f  is
          specified by POSIX.)

So you would use this as:

$ grep -e termA -e termB *
share|improve this answer
    
Thanks. Not quite what I'm after. Your example (with -l to display the files) will give me files tat have either termA or termB in them. I want a list of files that have both terms in. – Peter Howe Jul 11 '12 at 13:00

grep supports regular expressions as far as I know. I use the following syntax to search multiple terms:

    grep 'termA\|termB' /i/am/a/path

you do need to use the escape character '\' before each '|' but with that I bvelieve you can use as many search strings as you want

share|improve this answer
    
Sorry, I've clarified it in the question now, but I'm after a list of files with both terms in. This would give me a list of files with either in. – Peter Howe Jul 11 '12 at 13:03

You must log in to answer this question.

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