すべてのパターンがファイル内にあるか確認する

すべてのパターンがファイル内にあるか確認する

たとえば、patterns.txtあるファイル内にそれらのパターンがすべて存在するかどうかを確認したいとします。

次のようなことができます:

for pattern in $(cat patterns.txt); do 
  if ! grep -q "$pattern" file.txt; then
    echo "Error: missing pattern $pattern"
  fi
done
echo "All patterns found"

しかし、これは各パターンを再スキャンする必要があるため非効率的ですfile.txt(また、ファイルではなく、たとえば大きな可能性があるパイプからのストリーム内のパターンを検索する場合はそれほど単純ではありません)。

grep(または他のツールで)確認する方法はありますか?全てパターンは存在しますか?

答え1

cat file.txt | awk '
    NR == FNR {seen[$0] = 0; next} 
    {for (p in seen) if ($0 ~ p) seen[p]++} 
    END {
        for (p in seen) 
            if (seen[p] == 0) {
                missing++
                print "missing pattern", p
            } 
        if (missing == 0) print "all found"
        exit missing
    }
' patterns.txt -

catコマンドを、テキストを生成するパイプラインに置き換えます。

答え2

これはうまくいくかもしれません:

sort -u patterns.txt > sorted_patterns.txt # only once
diff -sq <(grep -o -f sorted_patterns.txt file.txt | sort -u) sorted_patterns.txt

パターンではなく固定文字列がある場合は、 を使用します-F。これにより、grep処理速度が大幅に向上します。

あなたは出来るまた使用するcmpの代わりに を使用しますdiff -s。少し速くなるかもしれませんが、何が欠けているかを表示することはできません。


すべてのパターンが見つからなかった場合は出力します。

Files /dev/fd/63 and /dev/fd/62 differ

またはすべてのパターンが見つかった場合:

Files /dev/fd/63 and /dev/fd/62 are identical

-q知るために残す不足している。

2a3
> missing_word

答え3

grepPCRE 拡張機能とコマンドの機能を使用すると、printf次のようになります。

<infile grep -qzP "(?s)$(printf "(?=.*?%s)" $(<pattern.txt))" &&
 echo 'all matched' ||
 echo 'one or more pattern(s) does not found'

すべてのパターン(任意の順序)が入力ファイルに見つかりましたインファイルテキストall matched出力されます。それ以外の場合はテキストone or more pattern(s) does not foundエコーします。

これは、パターンを一致パターンとして機能させ、& ;pat[01]の両方に一致させ、正確なパターンに一致させるには、文字通りに制御修飾子をからに変更し、特殊文字をエスケープします。pat0pat1pat[01]printf%s%q

<infile grep -qzP "(?s)$(printf "(?=.*?%q)" $(<pattern.txt))" &&
 echo 'all matched' ||
 echo 'one or more pattern(s) does not found'

関連情報