如何搜索包含一组单词的多行文本文件(例如,AAA & (BBB | CCC) & ~DD)?

wza*_*zab 9 grep find search text

我需要找到满足相对复杂条件的文件。例如,我想找到满足以下所有条件的所有文件:

  • 确实包含单词 AAAA
  • 确实包含单词 BBB 或 CCCCC(可能同时包含它们)
  • 不包含单词 DDD

这些词可能以任何顺序出现,也可能出现在不同的行中。

我有一个解决方案,它结合了findegrep,但不是很清晰。

find . \( -type f -and -exec egrep -q 'BBB|CCCCC' {} \; \
   -and -exec egrep -q AAAA {} \; \
   -and -not -exec egrep -q DDD {} \; \) -print
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法来解决这个问题?

Qua*_*odo 15

在我看来,您的解决方案对于这项任务非常清晰。但是,它很慢,因为它为每个文件生成 3 个进程。我想在awk是更好地在这里适用,因为它将使阅读整批处理文件在一个单一的去(如由ARG_MAX允许的),使用{} +代替{} \;

GNU awk:

find . -type f -exec gawk '
    BEGINFILE{c1=c2=c3=0}
    /AAA/       {c1=1}
    /BBB/||/CCC/{c2=1}
    /DDD/       {c3=1; nextfile}
    ENDFILE{if(c1 && c2 && !c3)print FILENAME}
' {} +
Run Code Online (Sandbox Code Playgroud)

POSIX * :

find . -type f -exec awk '
    FNR==1{
        if(NR>1 && c1 && c2 && !c3)print f
        c1=c2=c3=0
        f=FILENAME
    }
    /AAA/       {c1=1}
    /BBB/||/CCC/{c2=1}
    /DDD/       {c3=1; nextfile}
    END{if(c1 && c2 && !c3)print f}
' {} +
Run Code Online (Sandbox Code Playgroud)

*实际上,nextfile仍然不是 POSIX 但它已被接受到下一期标准。您可以删除它以符合 POSIX 问题 7;结果将是相同的,但会有性能损失。


注意:如果 awk 没有读取文件的权限,它会退出。在 GNU Find 中,只需添加-readable标志即可避免这种情况。如果 GNU Find 不可用,Test 可以用作附加过滤器:

find . -type f -exec test -r {} \; -exec awk '
    ...
' {} +
Run Code Online (Sandbox Code Playgroud)

但是为每个文件生成一个测试代表了性能损失。


进一步阅读: