私はUi\.
の後にLine
またはL
の文字さえも続かないすべてのインスタンスに対してgrepを試みています。
別の文字列が続かない特定の文字列のすべてのインスタンスを見つけるための正規表現を記述する適切な方法は何ですか?
先読みを使用する
grep "Ui\.(?!L)" *
bash: !L: event not found
grep "Ui\.(?!(Line))" *
nothing
ネガティブ先読みには、標準のgrep
よりも強力なツールが必要です。 PCRE対応のgrepが必要です。
GNU grep
がある場合、現在のバージョンはオプション-P
または --Perl-regexp
そして、必要な正規表現を使用できます。
(十分に最近のバージョン)GNU grep
がない場合は、 ack
を取得することを検討してください。
あなたの問題の一部に対する答えはここにあり、ackは同じように振る舞います: エラーを与える肯定的および否定的な先読み
Grepに二重引用符を使用しているため、bashは「_!
_を履歴展開コマンドとして解釈する」ことができます。
パターンを単一引用符で囲む必要があります:grep 'Ui\.(?!L)' *
ただし、 @ JonathanLeffler's answer を参照して、標準のgrep
!のネガティブな先読みの問題に対処してください。
おそらくgrepを使用して標準の負の先読みを実行することはできませんが、通常は「逆」スイッチ「-v」を使用して同等の動作を取得できるはずです。それを使用して、一致させたいものの補完のための正規表現を構築し、2 grepsにパイプすることができます。
問題の正規表現については、次のようなことをするかもしれません
grep 'Ui\.' * | grep -v 'Ui\.L'
負の先読みをサポートしない正規表現の実装を使用する必要があり、余分な文字*を一致させることを気にしない場合、 否定文字クラス_[^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]
_または_$
_。
この種の式は、非常に扱いにくく、短い文字列でもエラーが発生しやすくなります。式を生成するために何かを書くこともできますが、ネガティブな先読みをサポートする正規表現の実装を使用する方が簡単でしょう。
*実装が 非キャプチャグループ をサポートしている場合、余分な文字のキャプチャを回避できます。
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;};}"