13

I have a tree of source code and I am looking to find all files that contain a certain word and must not contain a second word. This, because I need to update older files to include some newer code.

I know I can use find, but I feel like if I try to chain grep statements it won't work because the second grep statement is going to be searching the results of the first and then I got lost.

I tried:

find . -type f -name "*.c" -exec grep -Hl "ABC" {} \; | grep -L "123"

And this totally did not work. Any help would be appreciated.

0

3 Answers 3

18

Since the exit status of grep indicates whether or not it found a match, you should be able to test that directly as a find predicate (with the necessary negation, ! or -not) e.g.

find . -type f -name "*.c" \( -exec grep -q "ABC" {} \; ! -exec grep -q "123" {} \; \) -print

-q makes grep exit silently on the first match - we don't need to hear from it because we let find print the filename.

3
  • Note that it runs at least one and up to two greps per C file. -q already stops at the first match. -m1 (a GNU extension) won't make any difference. Oct 8, 2016 at 21:58
  • 2
    @steeldriver:  I believe that you could leave out the \( and the \). Oct 9, 2016 at 6:27
  • Is grep "123" applied on results from first find/grep couple ?
    – Delphine
    Mar 7, 2018 at 14:17
8

Since you're already using GNU extensions:

find . -type f -size +2c -name "*.c" -exec grep -l --null ABC {} + |
  xargs -r0 grep -L 123

If you want to do something else with those files:

find . -type f -size +2c -name "*.c" -exec grep -l --null ABC {} + |
  xargs -r0 grep -L --null 123 | xargs -r0 sh -c '
    for file do
      something with "$file"
    done' sh {} +

Or with zsh or bash:

find . -type f -size +2c -name "*.c" -exec grep -l --null ABC {} + |
  xargs -r0 grep -L --null 123 |
  while IFS= read -rd '' file; do
    something with "$file"
  done
1

For complex constrains, I prefer using a programming language: Awk

find -name '*.c' \
   -exec awk -v RS="\0" '/ABC/ && !/123/{print FILENAME}' {} \; 

You must log in to answer this question.

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