如何查找包含一个条件但排除另一条件的文件

如何查找包含一个条件但排除另一条件的文件

我有一个源代码树,我正在寻找包含某个单词且不得包含第二个单词的所有文件。这是因为我需要更新旧文件以包含一些新代码。

我知道我可以使用 find,但我觉得如果我尝试链接 grep 语句,它将不起作用,因为第二个 grep 语句将搜索第一个 grep 语句的结果,然后我迷路了。

我试过:

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

这完全行不通。任何帮助,将不胜感激。

答案1

由于 的退出状态grep指示它是否找到匹配项,因此您应该能够直接将其作为find谓词进行测试(带有必要的否定,!-not),例如

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

-q在第一场比赛中静默grep退出 - 我们不需要听到它的消息,因为我们让find打印文件名。

答案2

由于您已经在使用 GNU 扩展:

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

如果您想对这些文件执行其他操作:

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 {} +

或者用zshor 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

答案3

对于复杂的约束,我更喜欢使用编程语言:Awk

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

相关内容