複数のANDパターンでgrepを実行する方法は?


86

パターン間で暗黙的なANDを使用したマルチパターンマッチを取得したいと思います。つまり、シーケンスで複数のgrepsを実行するのと同じです。

grep pattern1 | grep pattern2 | ...

それをどのように変換するのですか?

grep pattern1 & pattern2 & pattern3

引数を動的に構築するため、単一のgrepを使用したいので、すべてが1つの文字列に収まらなければなりません。フィルターの使用はシステム機能であり、grepではないため、それは引数ではありません。


この質問と以下を混同しないでください。

grep "pattern1\|pattern2\|..."

これはORマルチパターンマッチです。



回答:


79

agrep この構文でそれを行うことができます:

agrep 'pattern1;pattern2'

GNU grepでは、PCREサポートを使用してビルドすると、次のことができます。

grep -P '^(?=.*pattern1)(?=.*pattern2)'

ASTgrep

grep -X '.*pattern1.*&.*pattern2.*'

(追加.*として複数可<x>&<y>両方に一致する文字列と一致する<x><y> 、正確にa&bすることができ、そのような文字列がないとマッチしないだろうことの両方ab同時に)を。

パターンが重複しない場合は、次のこともできる場合があります。

grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'

おそらく、awkすでに述べたように、最良のポータブルな方法は次のとおりです。

awk '/pattern1/ && /pattern2/'

sed

sed -e '/pattern1/!d' -e '/pattern2/!d'

これらはすべて異なる正規表現構文を持つことに注意してください。


1
agrep構文は、それが中に導入されたバージョン...私のために働いていないのですか?
ラマン

1992年の @Raman 2.04にはすでに含まれていました。最初から存在していなかったと信じる理由はありません。glimpse / webglimpseには、新しい(1992年以降)バージョンがagrep含まれています。おそらく、別の実装があります。ast-grepバージョンの間違いがありましたが、拡張正規表現のオプションはです。-X-A
ステファンシャゼル

@StéphaneChazelasありがとう、agrepFedora 23 には0.8.0があります。これはagrepあなたが参照したものとは違うようです。
ラマン

1
@Raman、あなたはTREのagrepように聞こえます。
ステファンシャゼル

2
@Techiee、またはちょうどawk '/p1/ && /p2/ {n++}; END {print 0+n}'
ステファンシャゼラス

19

grepバージョンを指定しませんでした。これは重要です。正規表現エンジンの中には、「&」を使用してANDでグループ化された複数の一致を許可するものがありますが、これは非標準で移植性のない機能です。しかし、少なくともGNU grepはこれをサポートしていません。

OTOH grepをsed、awk、perlなどに単純に置き換えることができます(重量の大きい順にリストされています)。awkでは、コマンドは次のようになります

awk '/ regexp1 / && / regexp2 / && / regexp3 / {print; } '

また、コマンドラインで簡単に指定できるように構築できます。


3
ただ、それは覚えているawkのと同等例えば、EREのを使用していますgrep -EBREのその平野とは反対に、grep用途。
jw013

3
awkの正規表現はERE と呼ばれますが、実際には少し特異です。おそらく誰もが気にかけているよりも詳細な情報があります:wiki.alpinelinux.org/wiki/Regex
dubiousjim

ありがとう、grep 2.7.3(openSUSE)。私はあなたを支持しましたが、私はしばらく質問を開いたままにします、多分grepのためのいくつかのトリックがあるかもしれません(私は嫌いではありませんawk-単により多くを知っている方が良いです)。
greenoldman

2
デフォルトのアクションは、一致する行を印刷する{ print; }ことです。そのため、この部分は実際には不要または有用ではありません。
tripleee

7

patterns1行に1つのパターンが含まれている場合、次のようなことができます。

awk 'NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1' patterns -

または、これは正規表現ではなく部分文字列に一致します。

awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns -

代わり場合の入力の無いラインのすべて印刷するにはpatterns空であるが、交換するNR==FNRFILENAME==ARGV[1]、またはでARGIND==1gawk

これらの関数は、引数として指定された各文字列を部分文字列として含むSTDINの行を出力します。gagrep allを表し、gai大文字と小文字を区別しません。

ga(){ awk 'FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1' <(printf %s\\n "$@") -; }
gai(){ awk 'FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1' <(printf %s\\n "$@") -; }

7

これはあまり良い解決策ではありませんが、ややクールな「トリック」を示しています

function chained-grep {
    local pattern="$1"
    if [[ -z "$pattern" ]]; then
        cat
        return
    fi    

    shift
    grep -- "$pattern" | chained-grep "$@"
}

cat something | chained-grep all patterns must match order but matter dont

1
いずれかを使用しchained-grep()たりfunction chained-grepではなくfunction chained-grep()unix.stackexchange.com/questions/73750/...
nisetama

3

git grep

ブールgit grepを使用して複数のパターンを組み合わせて使用する構文は次のとおりです。

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3

上記のコマンドは、すべてのパターンに一致する行を一度に印刷します。

--no-index Gitによって管理されていない現在のディレクトリ内のファイルを検索します。

man git-grepヘルプを確認してください。

こちらもご覧ください:

OR操作については、以下を参照してください。


1

ripgrep

以下が使用例rgです:

rg -N '(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)' file.txt

これは、最速のgreppingツールの1つです。これは、有限オートマトン、SIMD、および積極的なリテラル最適化を使用して非常に高速に検索するRustの正規表現エンジンの上に構築されているためです。

GH-875の関連機能リクエストもご覧ください。


1

これが私の見解です。これは複数行の単語に対して機能します。

を使用find . -type fして
-exec grep -q 'first_word' {} \;
、最後のキーワードと
-exec grep -l 'nth_word' {} \;

-q
-l一致するサイレント/サイレント ショーファイル

以下は、「rabbit」と「hole」という単語を含むファイル名のリストを返します。
find . -type f -exec grep -q 'rabbit' {} \; -exec grep -l 'hole' {} \;


-2

すべての単語(またはパターン)を見つけるには、FORループでgrepを実行します。ここでの主な利点は、正規表現のリストから検索することです。

実際の例を使用して私の答えを編集します。

# search_all_regex_and_error_if_missing.sh 

find_list="\
^a+$ \
^b+$ \
^h+$ \
^d+$ \
"

for item in $find_list; do
   if grep -E "$item" file_to_search_within.txt 
   then
       echo "$item found in file."
   else
       echo "Error: $item not found in file. Exiting!"
       exit 1
   fi
done

このファイルで実行してみましょう:

うん

ああああ

bbbbbbbbb

ababbabaabbaaa

ccccccc

dsfsdf

bbbb

cccdd

ああ

CAA

# ./search_all_regex_and_error_if_missing.sh

ああああああ

ファイルに^ a + $が見つかりました。

bbbbbbbbb bbbb

ファイルに^ b + $が見つかりました。

うん

ファイルに^ h + $が見つかりました。

エラー:^ d + $がファイルに見つかりません。終了!


1
あなたのロジックに欠陥があります-私はALL演算子を求めました、あなたのコードはOR演算子としてではなく、演算子として機能しますAND。ところで。そのため、(OR)は質問で与えられたはるかに簡単なソリューションです。
greenoldman

@greenoldmanロジックは単純です。for は、リスト内のすべての単語/パターンループし、ファイル内で見つかった場合は印刷します。単語が見つからなかった場合にアクションが必要ない場合は、elseを削除してください。
ノーム・マノス

1
私はあなたのロジックだけでなく、私の質問を理解して-私が求めていたAND、それはパターンAとパターンBとパターンCとが一致する場合にのみ正のヒットであるファイルを意味し、オペレータ... ANDそれが一致した場合にはケースファイルは正のヒットですパターンAまたはパターンBまたは...今、違いがわかりますか?
-greenoldman

@greenoldmanは、このループがすべてのパターンのAND条件をチェックしないと思う理由がわかりませんか?実際の例を使って答えを編集しました:リストのすべての正規表現をファイル内で検索し、最初に見つからないものについてはエラーで終了します。
ノーム・マノス

あなたは目の前にそれを持っている、あなたは最初のマッチが実行された直後にポジティブマッチを持っている。すべての結果を「収集」して計算ANDする必要があります。その後、スクリプトを書き直して複数のファイルで実行する必要があります。その場合、質問にすでに答えていることに気づきます。
greenoldman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.