6

I want to use find command to find some files containing multiple patterns at the same time.

I tried something like this:

find . -name "*.xml" -exec grep -iH keyword1 + && grep -iH "keyword2" {} \;

But the above command doesn't work.

Is it possible to do it in bash?

3 Answers 3

9

As I understand, you want to list files that contain both "keyword1" and "keyword2". To do that, you can use two -exec tests in following way:

find . -name "*.xml" -exec grep -iq keyword1 {} \; -exec grep -iH keyword2 {} \;

This will run the second grep conditionally - if the first one returned true. The -q option prevents output from the first grep, as it would list all the files that include only "keyword1".

Since the -H option outputs the matching line together with the file name, you'd probably want to use -l instead. So

find . -name "*.xml" -exec grep -iq keyword1 {} \; -exec grep -il keyword2 {} \;

This will yield similar output to what Caleb suggested, but without the need of additional -print.

2
  • Does this mean that find will always exit immediately when an -exec returns a non-zero value?
    – Peter.O
    Aug 27, 2011 at 22:02
  • Not exactly "exit". -exec is really a test that find performs on the file - and all the tests are by default chained using an and logic - see man find :) Aug 27, 2011 at 22:05
6

First, to do this with find you would add a second -exec argument. Each argument is only able to run one command. If you needed to run multiple things you would have to use a hack by making the one command a shell and running multiple commands. Here it is with find doing the work:

find . -name "*.xml" -exec grep -qi "keyword1" {} \; -exec grep -qi "keyword2" {} \; -print

Note that I have used finds -print option to output the files names instead of having grep do it and used the -q option of grep to put it in silent mode so that it simply gives a return code that can be used by find to tell if the result was true or not, then move on. If it reaches the last step (meaning both files have matched) it prints the output.

However this is inefficient because grep is actually having to scan all the files twice. If you meant your question literally this will have to do, but if you meant to find files containing ANY of the strings you can use grep to search for both patterns on one pass like this:

find . -name "*.xml" -exec grep -qi -e "keyword1" -e "keyword2" {} \; -print

Edit: It is unclear in your question what exactly you want to have happen, and the two examples I gave actually do different things. The first one is an AND operation and only prints files that contain both keywords and the second is an OR operation that prints the file name if it contains either string. Pick your poison.

5
  • I understand the question differently - you give a recipe for or logic, but the OP has && in his line, so he probably wants to find files that contain both keywords. Aug 27, 2011 at 20:56
  • Ah, I see you already corrected it. :) Aug 27, 2011 at 20:58
  • @rozcietrzewiacz: Your comment came in about 4 minutes after I fixed that oversight in my answer (probably while you were working up something similar in yours).
    – Caleb
    Aug 27, 2011 at 20:59
  • Probably :) And OldTimer's comment to my comment came even later :D Aug 27, 2011 at 21:06
  • It would be handy if the OP would come back and clarify. Since to me it now seems he wants to see all of the lines in the file that contain both words, not just the file names.
    – OldTimer
    Aug 28, 2011 at 16:49
0

Or just use egrep:

find . -name "*.xml" -exec egrep -iH "keyword1|keyword2" {} \;

4
  • 2
    This accomplishes a different search - you have or, the OP asked for and. Aug 27, 2011 at 20:31
  • If so, it seems none of us have the right answer at this time then.
    – OldTimer
    Aug 27, 2011 at 21:01
  • I think it was indeed so. But I see Caleb has just modified his answer according to that interpretation. Aug 27, 2011 at 21:04
  • I was trying to answer this myself with only regex, and I found a similar question on Unix.com, with an answer of word1.*word2|word2.*word1
    – Jodie C
    Mar 28, 2012 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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