How to find files containing two strings together in Linux?

I want to find files containing two strings together, for example the file contains both string1 and string2.

I want the full path of files in output. I don't want to see "permission denied" warnings.


grep -l string2 `grep -l string1 /path/*`

which is the same as

grep -l string2 $(grep -l string1 /path/*)

Edit: heres why grep string1 /path/* | grep string2 doesn't do what I think alwbtc wants.

$ cd /tmp
$ cat a
apples
oranges
bananas
$ cat b
apples
mangoes
lemons
$ cat c
mangoes
limes
pears
$ cd ~
$ grep apples /tmp/* | grep mangoes
$

Nothing found, but file b contains both strings.

Here's what I think alwbtc wants

$ grep -l apples $(grep -l mangoes /tmp/*)
/tmp/b

Here's the equivalent ack command to RedGrittyBrick's answer:

ack string2 $(ack string1 -l)

Works the same way (except ack by default searches the current directory recursively). The contents within the $() searches for string1 but -l outputs only the filenames where that string was found. They are then passed as arguments into the outer command, which means string2 is searched for within those list of files only.


I was looking for an extensible way to do 2 or more strings and came up with this:

grep -rl string1 path-to-files | xargs grep -l string2 | xargs grep -l string3

The first grep recursively finds the names of files containing string1 within path-to-files.

The results are piped into xargs which runs one or more grep commands on those files for string2.

The results are then piped into another xargs command for string3 - it's the same as the first xargs call, but looking for a different string.

The use of xargs will avoid problems where there are so many results that the resultant command line from the use of back-ticks is too long.

To avoid the warnings we can redirect stderr to /dev/null:

grep -rl string1 path-to-files  2>/dev/null | xargs grep -l string2

It's not needed on the subsequent grep calls because string1 has already been found inside the file so the permissions are known to be good.


Pipe one grep into another:

grep "string1" /path/to/files/* | grep "string2"