grep -wは行の最初のパターンのみを一致します。

grep -wは行の最初のパターンのみを一致します。

grep -w私はなぜ(GNU実装バージョン3.1)が1行で特定のパターンの最初の発生と一致するのかを理解しようとしています。

ここに例があります。n1、、、n2と一致すると予想しましたが、n3最初の項目にのみ一致します。

$ echo 'n1=1 n2=2 n3=3' | grep -ow "n[0-9]=*"
n1

n2または、ORのみを一致させるように指示すると、n3最初の項目と再一致して無視されますn3

$ echo 'n1=1 n2=2 n3=3' | grep -ow "n[23]=*" 
n2

私がここで何を見逃しているのでしょうか?この動作の説明はありますか?それともgrepの一種のバグですか?

アイデアは次のようなものです。

  1. n[0-9]単語以外の文字が前後に続きます。
  2. n[0-9]で始まり、その後に任意の数の文字が続き、単語ではなく文字で終わる=部分文字列です。

たとえば、文字列がある場合、n1=1 n2=== n3=3 n4== n5予想される結果は次のようになります。

n1
n2===
n3
n4==
n5

言う:私はこの目標が達成可能であることを知っていますが、grep -ow -e 'n[0-9]' -e "n[0-9]=*"それはポイントではありません。この質問の目的は、grepそれがどのように機能するかを理解することです。

追加テスト

n<num>=行の別の場所に追加すると(等号の後の後続の単語文字なし)、その文字も一致しますが再び無視されますn3=3

$ echo 'n1=1 n2= n3=3 n4=' | grep -ow "n[0-9]=*"
n1
n2=
n4=

私が最後に見つけたのは、パターンを解釈するPerl互換正規表現を追加すると、部分文字列の説明が-P保持されないようです。-w「行の末尾に来る必要があるか、単語を形成しない文字が後に続く必要があります。」n1=後ろに文字があっても一致するからです。1、これは単語を形成する文字(「文字、数字、下線」)。

$ echo 'n1=1 n2= n3=3 n4=' | grep -owP "n[0-9]=*"
n1=
n2
n3=
n4

grep -wPだから検索になると思います。単語の境界代わりに部分文字列の最後に牡丹形成文字。次のようになります。

$ echo 'n1=1 n2= n3=3 n4=' | grep -o "\bn[0-9]=*\b"
n1=
n2
n3=
n4

答え1

よく受けました。これはバグのようですgrep (3.4と3.7でテスト済みGNU grep)。

grep -ow "n[0-9]=*"
grep -Eow "n[0-9]=*"

最初の一致(または最初の一致のみを返す)のみを返します
が、...

grep -Pow "n[0-9]=*"

...予想どおりすべての一致を返します。

バグを報告するには、GNU grep以下を確認してください。ここ


しかし、私はあなたの観察を確認することはできません-P-w[...] 維持された説明がないようです。、私に(GNU grep 3.4および3.7)コマンドは期待どおりに出力されます。

$ echo 'n1=1 n2= n3=3 n4=' | grep -owP "n[0-9]=*"
n1
n2=
n3
n4=

答え2

たとえば、文字列がある場合、n1=1 n2=== n3=3 n4== n5予想される結果は次のようになります。

n1
n2===
n3
n4==
n5

説明:次の方法で達成できることを知っています。grep -ow -e 'n[0-9]' -e "n[0-9]=*"

これについてもわかりません。

u$ grep --version |head -1
grep (GNU grep) 2.27
u$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' | grep -ow -e 'n[0-9]' -e "n[0-9]=*"
n1
n2===
n3
n4==
n5

そして

a$ grep --version |head -1
grep (GNU grep) 3.4
a$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' | grep -ow -e 'n[0-9]' -e "n[0-9]=*"
n1
n2===
n4==
n5

n3最新のgrepがどのように欠けているかを確認してください。これはUbuntuにあり、結果は3.7と同じです。

Busyboxの場合、答えは異なります。

$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' | busybox grep -ow -e 'n[0-9]' -e "n[0-9]=*"
n1
n2
n3
n4
n5

私のMacのBSD grepもn1n2...などを印刷しますが、それぞれ2回ずつ印刷します。理由は何でも。

良いステファンはコメントでこう言いました。-wこの目的では移植性がないようです。


アイデアは次のようなものです。

  • n[0-9]単語以外の文字が前後に続きます。

  • n[0-9]で始まり、その後に任意の数の文字が続き、単語ではなく文字で終わる=部分文字列です。

あなたはPerlで次のようなものを実装したいと思います(=優先順位があるようにこの順序で):

/ n[0-9]=*(?=\W) | \bn[0-9]\b /x

例えば

$ printf '%s\n' 'n1=1 n2=== n3=3 n4== n5' |
    perl -lne 'print $& while / n[0-9]=*(?=\W) | \bn[0-9]\b /xg'
n1
n2===
n3
n4==
n5

しかし、これがあなたが望むものであるかどうかはわかりません。代わりに、n2===x出力n2===はになりますn2==。これは、最後の項目が=「単語以外の文字で終わる」句を満たすために使用されるためです。 (またはむしろ「後ろに」、そうでなければforへの一致もn1=1なります。n1=n1==

=*+シンボルの返却を避けるために所有修飾子を使用できると思います=

$ printf '%s\n' 'n1=1 n2===X n3=3 n4== n5' |
    perl -lne 'print $& while / n[0-9]=*+(?=\W) | \bn[0-9]\b /xg'
n1
n2
n3
n4==
n5

とにかく、あなたが望むものが簡単なロジックでよりよく達成できるかどうか疑問に思います。つまり、文字列を空白に分割し、部分文字列を記号に分割し=、個々の値を見てください。

関連情報