`^[ ]{0,}` が Linux grep で動作しないのはなぜですか?

`^[ ]{0,}` が Linux grep で動作しないのはなぜですか?

これは私のサンプルテキストです。grep w、非常にうまく動作しますgrep ^wgrep '^[ ]w'

[user@linux ~]$ grep w text.txt
whitespace 0
 whitespace 1
  whitespace 2
[user@linux ~]$

[user@linux ~]$ grep ^w text.txt
whitespace 0
[user@linux ~]$

1つのスペースがあります

[user@linux ~]$ grep '^[ ]w' text.txt
 whitespace 1
[user@linux ~]$

スペースは2つありますが、同じ出力を取得します。

[user@linux ~]$ grep '^[  ]w' text.txt
 whitespace 1
[user@linux ~]$

~によるとhttps://regex101.com/^[ ]{0,}、行の先頭で空白を探す正しい構文です。しかし、LinuxのGNU grepでは正しく動作しません。エラーが発生しますInvalid regular expression

[user@linux ~]$ grep ^[ ]{0,}w text.txt
grep: Invalid regular expression
[user@linux ~]$

これらはまったく何も返しません

[user@linux ~]$ grep '^[ ]{0}w' text.txt
[user@linux ~]$ grep '^[ ]{1}w' text.txt
[user@linux ~]$ grep '^[ ]{2}w' text.txt
[user@linux ~]$ grep '^[ ]{0,}w' text.txt
[user@linux ~]$

Q:^[ ]{0,}GNU grepで使用できますか?それでは、以前の文法にはどのような問題がありましたか?

答え1

これにはあらゆる種類の問題があります。まず、式の^[ ]w意味は次のとおりです。行の先頭を見つけて、まったく1つのスペースを見つけてから1つを見つけますw。だから実際にはかなりうまくいきます。 1つ以上のスペースを一致させるには、[ ]文字クラスに修飾子を追加する必要があります。

  $ grep '^[  ]\+w' text.txt
 whitespace 1
  whitespace 2

+「1つ以上」を意味します。使用されるデフォルトの正規表現スタイルはgrepBRE(基本正規表現)と呼ばれ、この正規表現スタイルでは+エスケープが必要なので、\+上記の*。あるいは、フラグを渡して拡張正規表現(ERE)を使用する-Eか、-Pフラグを渡してPCRE(Perl互換正規表現)を使用することもできます。これらの正規表現スタイルを使用すると、数量子として機能する+ためにエスケープする必要はありません。

$ grep -P '^[  ]+w' text.txt
 whitespace 1
  whitespace 2
$ grep -E '^[  ]+w' text.txt
 whitespace 1
  whitespace 2

次の問題であり、さらに重要な問題は、正規表現を引用しないことです。正規表現を渡すには引用符が必要です。grep 現状のままシェルによって最初に解釈されません。しかし、引用しなかったので、に渡される前にシェルによって拡張されますgrepset -xシェルに実行中のジョブを印刷させるオプションを使用して、これを確認できます。

$ set -x
$ grep ^[ ]{0,}w text.txt
+ grep '^[' ']0w' ']w' text.txt
grep: Invalid regular expression

^[まず、との間にスペースがあるため、]シェルはこれを2つの別々の引数^[と解釈します]{0,}w。ただし、{}支柱の拡張のためにシェルで使用されます。たとえば、

$ echo foo{a,b}
fooa foob

ただし、拡張の2番目の部分が空の場合、次の結果が表示されます。

$ echo foo{a,}
fooa foo

したがって、拡張は次]{0,}wのようになります。

$ echo ]{0,}w
]0w ]w

その結果、set -x上記の出力からわかるように、これら3つのパラメータは実際に次に渡されますgrep

'^[' ']0w' ']w'

ただし、引用する場合は、+上記のようにBREを使用するときにエスケープする必要があります。

$ grep '^[ ]\{2\}w' text.txt
  whitespace 2

最後の注意:[ ]まったく同じです。個々の文字に対して文字クラスを使用することは意味がありません。

これらすべてをまとめて、行の先頭で正確に1つのスペースと一致させるには、次のようにします。

$ grep '^ w' text.txt 
 whitespace 1

1 つ以上を一致させるには、次を使用します。

$ grep '^ \+w' text.txt 
 whitespace 1
  whitespace 2

または:

$ grep -E '^ +w' text.txt 
 whitespace 1
  whitespace 2

または

$ grep -P '^ +w' text.txt 
 whitespace 1
  whitespace 2

特定の数値範囲(たとえば、スペース0、1、2など)と一致させるには、次の手順を実行します。

$ grep '^ \{0,3\}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

または

$ grep -P '^ {0,3}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

または

$ grep -E '^ {0,3}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

特定の数字と一致させるには、{}上記のように数字を設定するか、文字をN回繰り返します。

$ grep '^ \{2\}w' text.txt
  whitespace 2
$ grep '^ w' text.txt
 whitespace 1
$ grep '^  w' text.txt
  whitespace 2

そして常に正規表現を引用してください!


*実際にPOSIX BREでは+特別な意味はありませんが、BREのGNU実装はgrepエスケープされるとそれを認識します。

答え2

BREでは、欲張りな数量式で{0,}目的の正規表現マッチングを達成するには、中かっこをエスケープする必要があります。引用する正規表現文字列。引用符がない場合、シェルは提供された引数に独自の構文解析構文を適用しようとし、ほとんどの場合、引数は正規表現の一部のみが表示されるようにgrepトークン化されます。^[

grep '^[ ]\{0,\}w' file

~から正規表現参照:数量子そしてGNU BREを選択してください

\{n,\}n >= 0前の項目の1つ以上が繰り返されますn。欲張りなので、前の項目がn回だけ一致するまで、できるだけ多くの項目を一致させた後、前の項目があまり一致しない順列を試みます。

コメントで指摘したように、 using は*modifier を使用するのと同じです\{0,\}

答え3

正しいコマンド:

使用grep -E '^[ ]{0,}' text.txt

-E、--extended-regexp PATTERNを拡張正規表現(ERE、以下を参照)として解釈します。

機能しない理由:

正規表現の周りに一重引用符を使用しないでください。 bashがそれを開き、コマンドは次のようになります。

grep '^[' ] ]0 text.txt正規表現を使用してgrep'^['ファイルに変換されます]]0text.txt

^[[特殊文字にも終了文字が必要なため、間違っています。]

-Eオプションが必要な理由:

{m,n} は拡張正規表現です。これを使用するには、grepに-Eオプションが必要です。

関連情報