web-dev-qa-db-ja.com

grepの「後に続かない」ための正規表現の先読み

私はUi\.の後にLineまたはLの文字さえも続かないすべてのインスタンスに対してgrepを試みています。

別の文字列が続かない特定の文字列のすべてのインスタンスを見つけるための正規表現を記述する適切な方法は何ですか?

先読みを使用する

grep "Ui\.(?!L)" *
bash: !L: event not found


grep "Ui\.(?!(Line))" *
nothing
90
Lee Quarella

ネガティブ先読みには、標準のgrepよりも強力なツールが必要です。 PCRE対応のgrepが必要です。

GNU grepがある場合、現在のバージョンはオプション-P または --Perl-regexpそして、必要な正規表現を使用できます。

(十分に最近のバージョン)GNU grepがない場合は、 ack を取得することを検討してください。

127

あなたの問題の一部に対する答えはここにあり、ackは同じように振る舞います: エラーを与える肯定的および否定的な先読み

Grepに二重引用符を使用しているため、bashは「_!_を履歴展開コマンドとして解釈する」ことができます。

パターンを単一引用符で囲む必要があります:grep 'Ui\.(?!L)' *

ただし、 @ JonathanLeffler's answer を参照して、標準のgrep!のネガティブな先読みの問題に対処してください。

35
NHDaly

おそらくgrepを使用して標準の負の先読みを実行することはできませんが、通常は「逆」スイッチ「-v」を使用して同等の動作を取得できるはずです。それを使用して、一致させたいものの補完のための正規表現を構築し、2 grepsにパイプすることができます。

問題の正規表現については、次のようなことをするかもしれません

grep 'Ui\.' * | grep -v 'Ui\.L'
8
Karel Tucek

負の先読みをサポートしない正規表現の実装を使用する必要があり、余分な文字*を一致させることを気にしない場合、 否定文字クラス_[^L]_ 、-を使用できます 代替_|_ 、および 文字列アンカーの終わり_$_

あなたの場合、grep 'Ui\.\([^L]\|$\)' *が仕事をします。

  • _Ui\._は、関心のある文字列と一致します

  • \([^L]\|$\)は、L以外の任意の1文字に一致します。または、行末に一致します:_[^L]_または_$_。

複数の文字を除外したい場合は、さらに多くの代替と否定をスローする必要があります。 aが続かないbcを見つけるには:

grep 'a\(\([^b]\|$\)\|\(b\([^c]\|$\)\)\)' *

aの後にbが続かないか、行の末尾が続く:aの後に_[^b]_または_$_)または(aの後にbが続き、その後にcが続かないか、行の最後が続く:a then b、then _[^c]_または_$_。

この種の式は、非常に扱いにくく、短い文字列でもエラーが発生しやすくなります。式を生成するために何かを書くこともできますが、ネガティブな先読みをサポートする正規表現の実装を使用する方が簡単でしょう。

*実装が 非キャプチャグループ をサポートしている場合、余分な文字のキャプチャを回避できます。

3
dougcosine

Grepが-Pまたは--Perl-regexpをサポートしていない場合、PCRE対応のgrepをインストールできます。 「pcregrep」、GNU grepのようなコマンドラインオプションを必要とせず、Perl互換の正規表現を受け入れるため、単に実行します

pcregrep "Ui\.(?!Line)"

例の「Ui。(?!(Line))」のように、「Line」に別のネストされたグループは必要ありません。上に示したように、外側のグループで十分です。

ネガティブアサーションを探す別の例を挙げましょう。「ipset」によって返される行のリストがあり、各行が行の中央にあるパケットの数を示しており、ゼロパケットの行が必要ない場合は、実行:

ipset list | pcregrep "packets(?! 0 )"

Perl互換の正規表現が好きで、Perlはあるがpcregrepがない、またはgrepが--Perl-regexpをサポートしていない場合、grepと同じように機能する1行のPerlスクリプトを使用できます。

Perl -e "while (<>) {if (/Ui\.(?!Lines)/){print;};}"

Perlはgrepと同じ方法でstdinを受け入れます。

ipset list | Perl -e "while (<>) {if (/packets(?! 0 )/){print;};}"
0
Maxim Masiutin