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 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.

share|improve this question
up vote 6 down vote accepted
grep -l string2 `grep -l string1 /path/*`

which is the same as

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

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

$ cd /tmp
$ cat a
$ cat b
$ cat c
$ 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/*)
share|improve this answer
This is a neat solution and more useful than mine. For those that want to know what is going on here (it took me a bit to figure out), he's using the -l option to return the file names instead of the lines. He's then using the dollar sign or the back quotes to pass that list as the FILE argument into the second grep. This allows the second grep to search the entirety of each file found instead of the individual lines as in my solution. – embedded.kyle Jun 18 '12 at 14:12
You missed a -l option for both commands to be considered equal. – Christian Sep 11 '13 at 11:12

Pipe one grep into another:

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

share|improve this answer
If the two strings are on different lines in the file, this wont work. – RedGrittyBrick Jun 15 '12 at 20:01
I didn't know there was a requirement for them to be in the same line @RedGrittyBrick – slhck Jun 15 '12 at 21:35
@slhck: I've updated my answer to show what I think alwbtc wants and why this answer doesn't do that. Of course, I may have misunderstood what alwbtc wants and embedded.kyle may have got it right - I suspect not though. – RedGrittyBrick Jun 15 '12 at 22:28
comm -12 <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort) <(grep --fixed-strings --files-with-matches "STRING1" /path/to/files/* 2>/dev/null | sort)

or less redundantly:

search_files () { str="$1"; shift; grep -Fl "$str" "$@" 2>/dev/null | sort; }
comm -12 <(search_files "STRING1" /path/to/files/*) <(sf "STRING2" /path/to/files/*)

This will work if the strings are on different lines of the same file and will also avoid false positives if a filename contains one of the strings.

share|improve this answer

To elaborate on @RedGrittyBrick's solution which has a shortcoming when running the command unattended plus to suppress error output as intended and to find files recursively you might consider

grep -l 'STRING1' $(! grep -lrs 'STRING2' /absolute/path/to/search/dir && echo /dev/null)

-s option will suppress error messages
-r option allows to search for strings in arbitrarily nested directories
! combined with && echo /dev/null guarantees that the command won't hang up. Otherwise, if the inner grep doesn't find any file it won't output anything so that the outer grep will indefinitely wait for input to search upon. This solution outputs /dev/null in these cases so outer grep will search for STRING1 in /dev/null where it's supposed to not finding anything.

share|improve this answer

You must log in to answer this question.

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