Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question

3 Answers 3

up vote 5 down vote accepted

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.

share|improve this answer
    
Does this mean that find will always exit immediately when an -exec returns a non-zero value? –  Peter.O Aug 27 '11 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 :) –  rozcietrzewiacz Aug 27 '11 at 22:05

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.

share|improve this answer
    
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. –  rozcietrzewiacz Aug 27 '11 at 20:56
    
Ah, I see you already corrected it. :) –  rozcietrzewiacz Aug 27 '11 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 '11 at 20:59
    
Probably :) And OldTimer's comment to my comment came even later :D –  rozcietrzewiacz Aug 27 '11 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 '11 at 16:49

Or just use egrep:

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

share|improve this answer
    
This accomplishes a different search - you have or, the OP asked for and. –  rozcietrzewiacz Aug 27 '11 at 20:31
    
If so, it seems none of us have the right answer at this time then. –  OldTimer Aug 27 '11 at 21:01
    
I think it was indeed so. But I see Caleb has just modified his answer according to that interpretation. –  rozcietrzewiacz Aug 27 '11 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 –  JodieC Mar 28 '12 at 15:52

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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