`^[ ]{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エスケープされるとそれを認識します。

おすすめ記事