grepで貪欲でない一致を行う方法は?


回答:


276

あなたは貪欲でない(または怠惰な)マッチを探しています。正規表現で貪欲でない一致を取得する?には、数量詞の後に修飾子を使用する必要があります。たとえば、あなたが変更することができます.*.*?.

デフォルトでgrepは、貪欲でない修飾子はサポートされていませんがgrep -P、Perl構文を使用できます。


3
eegg:dot all修飾子はマルチラインとも呼ばれます。「。」を変更する修飾子です。改行を含めるように動作を一致させます(通常は含まれません)。grepにはそのような修飾子はありませんが、pcregrepにはあります
A.ウィルソン

1
修正:これをサポートするほとんどの正規表現では、.改行を一致させることができるモードはDOTALLまたは単一行モードと呼ばれます。Rubyはmultilineと呼ばれる唯一のものです。他のフレーバーでは、マルチラインはアンカー(^および$)が行の境界で一致することを可能にするモードです。Rubyでは同等のモードがないため、Rubyでは常にそのように動作します。
アランムーア

5
-P was a complete new one on me, I've been happily grepping away for years, and only using -E ... so many wasted years! - Note to self: Re-read Man pages as a (even more!) regular thing, you never digest enough switches and options.
ocodo

29
On some platforms (like Mac OS X) grep does not support -P, but if you use egrep you can use the .*? pattern to achieve the same result. egrep -o 'start.*?end' text.html
SaltyNuts

4
As an extension to @SaltyNuts comment, Mac OS X does not support -P but -E would call egrep hence the suggested .*? works just fine.
Fredrik Erlandsson

83

Actualy the .*? only works in perl. I am not sure what the equivalent grep extended regexp syntax would be. Fortunately you can use perl syntax with grep so grep -P would work but grep -E which is same as egrep would not work (it would be greedy).

See also: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html


9
grep -P does not work in GNU grep 2.9 -- just tried it (it doesnt error, just silently doesn't apply the ?. Intertestly neither does the not class eg: env|grep '[^\=]*\='
roberto tomás

2
There's no grep -P option or pgrep command in Darwin/OS X 10.8 Mountain Lion, but egrep works great.
Steve HHH

2
pgrep私のOS X 10.9ボックスにはコマンドがありますが、それは「名前でプロセスを検出またはシグナル通知する」ことを目的とする完全に異なるプログラムです。
Desty、2014

@robertotomásここで6年前のコメントに応答しますが、これも同じように考えて、貪欲でない複数の一致を取得していることに気付きました。たとえば、カラーターミナルでは、 `echo" bbbbb "| grep -P 'b。*?b'`は2つの一致を返します。
zzxyz 2017年

12

このスレッドで何かを試した後に動作する私のgrep:

echo "hi how are you " | grep -shoP ".*? "

行のそれぞれにスペースを追加してください

(私は単語を吐き出すための行ごとの検索でした)


3
-shoPニーモニック:)
Mariusz

echo "bbbbb" | grep -shoP 'b.*?b'少しの学習経験です。明示的に怠惰の面でも私のために働いた唯一のもの。
zzxyz 2017年

12

grep

の貪欲でない一致でgrepは、否定された文字クラスを使用できます。つまり、ワイルドカードを使用しないようにします。

たとえば、ページコンテンツからjpegファイルへのすべてのリンクを取得するには、次のようにします。

grep -o '"[^" ]\+.jpg"'

複数のラインを処理するには、xargs最初に入力をパイプします。パフォーマンスについては、を使用してくださいripgrep


3

短い答えは次の正規表現を使用しています:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (?s)-これは複数行にわたって一致します
  • 。*?-怠惰な方法で任意の文字に何度も一致します(最小一致)

(少し)より複雑な答えは次のとおりです。

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

これにより、次のテキストのcar1とcar2を一致させることができます。

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..)はキャプチャグループを表します
  • このコンテキストの\ 1は、グループ番号1をキャプチャすることによって最後に一致したものと同じテキストに一致します

1

申し訳ありませんが9年遅れていますが、2020年の視聴者にはこれが役立つかもしれません。

したがって、次のような行があるとします"Hello my name is Jello"。ここで、で始まり、'H'で終わり'o'、間に任意の数の文字がある単語を検索します。そして、私達は単にラインが欲しいのではなく、単にラインが欲しいのです。そのため、次の式を使用できます。

grep "H[^ ]*o" file

これはすべての単語を返します。これが機能する方法は、次のとおりです。その間にスペース文字の代わりにすべての文字を許可します。これにより、同じ行に複数の単語が含まれるのを回避できます。

これで、スペース文字を必要な他の文字に置き換えることができます。最初の行がだったとすると、次"Hello-my-name-is-Jello"の式を使用して単語を取得できます。

grep "H[^-]*o" file

0

私はそれが少し死んだ投稿であることを知っていますが、これがうまくいくことに気づきました 出力からクリーンアップとクリーンアップの両方が削除されました。

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.