単語セット(AAAA&(BBB | CCCCC)&〜DDDなど)を含むテキストファイルを検索するにはどうすればよいですか?

単語セット(AAAA&(BBB | CCCCC)&〜DDDなど)を含むテキストファイルを検索するにはどうすればよいですか?

比較的複雑な基準を満たすファイルを見つける必要があります。たとえば、次の条件をすべて満たすすべてのファイルを検索したいとします。

  • AAAAという言葉が含まれています。
  • BBBまたはCCCCC(両方可能)という単語が含まれています。
  • DDDという単語は含まれていません。

単語は、順序に関係なく他の行(または同じ行)に表示できます。

find結合されたソリューションがありますが、egrep明確ではありません。

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

この問題を解決するより良い方法はありますか?

答え1

あなたの解決策は仕事にとって非常に明確であるようです。ただし、ファイルごとに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}
' {} +

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

*実はnextfileまだPOSIXではありませんが以下の規格により承認された。。 POSIX Issue 7コンプライアンスのためにそれらを削除できます。結果は同じですが、パフォーマンスに影響します。


ノート:awkにファイルを読み取る権限がない場合は終了します。 GNU Findでこの-readableフラグを追加すると、これを防ぐことができます。 GNU Findが利用できない場合は、Testを追加のフィルタとして使用できます。

find . -type f -exec test -r {} \; -exec awk '
    ...
' {} +

ただし、各ファイルのテストを生成するとパフォーマンスが低下します。


追加資料:

答え2

別のアプローチがあります。まず、各単語を含むファイルのリストを生成して動作します。

find . -type f -exec grep -lF 'AAA' {} + > files_with_AAA
find . -type f -exec grep -lF 'BBB' {} + > files_with_BBB
...

その後、リストを処理して条件を実装できます。

grep -xFf files_with_BBB files_with_AAA   # AAA & BBB
grep -xFvf files_with_BBB files_with_AAA  # AAA & ~BBB
sort -u files_with_AAA files_with_BBB    # AAA | BBB

評価するファイル数が多く、式が複数ある場合は、各ファイルを再スキャンする必要がないため、速度が速くなります。

答え3

特にこれらのソリューションとの時間比較を見たいと思います。リップグレップ、並列処理機能が内蔵されています。

  1. そしてGNU grep

    grep -rLZ 'DDD' | xargs -0 grep -lZ 'AAAA' | xargs -0 grep -lE 'BBB|CCCCC'
    
    # if your search terms are literal strings
    grep -rLZF 'DDD' | xargs -0 grep -lZF 'AAAA' | xargs -0 grep -lF -e 'BBB' -e 'CCCCC'
    
  2. そしてrg。再帰検索はデフォルトで有効になっており、一部のファイルもデフォルトで無視されます。そのファイルが結果に影響を与え-uないようにするには、この作業が必要です。隠しファイルをさらに検索します.gitignore。バイナリも検索するには を使用します。-uu-uuu

    rg --files-without-match -0  'DDD' | xargs -0 rg -l0  'AAAA' | xargs -0 rg -l 'BBB|CCCCC'
    
    # if your search terms are literal strings
    rg --files-without-match -0F 'DDD' | xargs -0 rg -l0F 'AAAA' |
                                         xargs -0 rg -lF -e 'BBB' -e 'CCCCC'
    
  3. rg複数行が一致する場合

    rg -lUP '(?s)\A(?!.*DDD)(?=.*(BBB|CCCCC)).*AAAA'
    

関連情報