Find files containing one string but not the other

As long as your filenames do not contain spaces, tabs, newline or wildcard characters, and if your grep supports the -L option, you can do it as follows:

$ cat file1
stringA
stringC
$ cat file2
stringA
stringB
$ grep -L stringB $(grep -l stringA file?)
file1

The grep executed in the subshell $(), will print all filenames which contain stringA. This filelist is input for the main grep command, which lists all files that do not contain stringB.

From man grep

  -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v is specified by POSIX.)

  -L, --files-without-match
          Suppress normal output; instead print the name of each input file from which no output would normally have been printed.  The scanning will stop on the first match.

  -l, --files-with-matches
          Suppress normal output; instead print the name of each input file from which output would normally have been printed.  The scanning will stop on the first match.  (-l is specified by POSIX.)

With GNU tools:

grep -lZ stringA ./*.txt |
  xargs -r0 grep -L stringB

-L, -Z, -r, -0 are GNU extensions sometimes but not always found in some other implementations.

Tags:

Grep

Find

Files