0

I am trying to search all files in a directory (and all subdirectories) for a string. If the file has that string, I then want to search for the number of times another string occurs, in this case "snake" and output it. I would also like to output the lines on which "snake" occurs within the file.

echo "Files with Reptile:"
find . -type f -name "*.txt" -exec grep -l "Reptile" {} \;

My challenge is how I add additional grep commands after the curly brackets. I have tried a couple of things and keep getting a "missing argument to -exec" error.

Am I trying to stuff too much into this find?

Thanks

asked Nov 9, 2017 at 0:43

3 Answers 3

1

You could try the following:

$ find . -type f -name "*.txt" -exec sh -c "grep -l "Reptile" {} | xargs -I% grep -Hn snake %" \;
./rep1.txt:2:snake
./rep2.txt:5:another snake

Output contains colon-delimited lists in which the first argument is the file name (from the -H argument to grep), the second argument is the line number on which the desired term appears (from the -n argument to grep), and the third argument is the line itself.

The xargs can be moved outside the find, giving you:

$ find . -type f -name "*.txt" -exec grep -l "Reptile" {} \; | xargs -i grep -Hn snake {}

Note that the -i argument to xargs (which is equivalent to -I{} is deprecated but I use it often for convenience.

Input files:

$ tail -n+1 rep*.txt
==> rep1.txt <==
Reptile
snake
iguana
crocodile
==> rep2.txt <==
Reptile
alligator
turtle
another snake
komodo dragon
==> rep3.txt <==
Reptile
lizard
gecko

If you need to deal with malformed file names, you can think about incorporating print0 and the -0 option to xargs.

answered Nov 9, 2017 at 0:58
1

Multiple -exec predicates. Since -exec is only true if the command succeeds, you don't need to do anything special with the first grep.

find ... -exec grep -q "Reptile" {} \; -exec grep -Hn snake {} \;
answered Nov 9, 2017 at 1:11
1
  • +1 for pointing out that -exec predicates are conditionally dependent on preceding ones Commented Nov 9, 2017 at 1:14
0
find . -type f -name "*.txt" -exec sh -c 't=$(mktemp)
 for fi
 do
 if grep -q Reptile "$fi"
 then
 echo "$fi contains Reptile"
 grep snake "$fi" | tee "$t"
 echo "snake appeared on $(wc -l < "$t") line(s)"
 fi
 done
 rm -f "$t"
 ' sh {} +

This reports the names of files that contain the word/string "Reptile", even if they don’t contain the word "snake", and independently reports the number of lines that contain "snake".

Oops; I misread the question, and thought that was a requirement. Taking it out is easy:

find . -type f -exec sh -c '
 for fi
 do
 if grep -q Reptile "$fi"
 then
 echo "$fi contains Reptile"
 grep snake "$fi"
 fi
 done
 ' sh {} +

You can add a -n option to the grep snake if you want.

This should handle just about any valid filename. Check the other answer(s) with filenames beginning with space and/or containing newline.

answered Nov 9, 2017 at 1:05

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.