1. ホーム
  2. regex

[解決済み] Grepの「Invalid range end」-バグか機能か?

2022-03-13 10:24:52

質問

以下の3つのファイルがあります。

$ cat pattern-ok 
['\-]
$ cat pattern-buggy 
[\-']
$ cat text 
abc'def-ghi

で、次は、私の知らないバグなのか、正規表現機能なのか?

$ cat text | grep -f pattern-ok 
abc'def-ghi
$ cat text | grep -f pattern-buggy
grep: Invalid range end

使っています。

$ grep --version | head -n 1
grep (GNU grep) 2.20

解決方法は?

これは、ハイフンを他の文字の中で使っているからで、そのため grep はそれを範囲として理解しますが、これはたまたま無効でした。

基本的に行っているのは

grep "[\-']" file

で解釈されます。 grep のように、チェックする文字の範囲を指定したものとして扱います。 grep "[a-z]" file . しかし \ から ' は無効であるため、エラーとなります。

そして、なぜもう一方が動作しているのか?という疑問が湧くかもしれませんね。なぜなら、あなたがやっていることは

grep "['\-]" file

この場合、文字列のどちらかを探しています。 ' , \ または - をファイル内に記述します。

別の例で、文字を見つけたい場合を見てみましょう。 a , - または 3 を指定された文字列の中に入れてください。

$ echo "23-2" | grep -o '[a-3]'
grep: Invalid range end
$ echo "23-2" | grep -o '[a3-]'
3
-
$ echo "23-2" | grep -o '[a3\-]'
3
-

つまり、根本的な問題は、式を使っていることです。 some character + - + another character の中に [] ブロックの間にある文字の範囲として読み取ろうとします。 some characteranother character .


どうすれば解決できるのか?

文字にマッチさせたい場合 - を式の端に追加するだけで、最初か最後の項目として追加できます。

から man grep :

文字クラスとブラケット表現

ブラケット式は、[ と ]で囲まれた文字のリストです。 これは は、そのリストに含まれる任意の1文字にマッチします。 である場合、そのリストに含まれないすべての文字にマッチします。 のリストです。 例えば、正規表現 [0123456789] は、以下のものにマッチします。 任意の1桁の数字。

ブラケット表現内。 範囲式は、2つの ハイフンで区切られた文字 . これは、任意の1文字 この2つの文字の間をロケールの 照合順序と文字セット。 例えば,デフォルトのC ロケールの場合、[a-d]は[abcd]と同じです。 多くのロケールでは、文字のソート は辞書順であり、これらのロケールでは [a-d] は一般的に abcd]と等価ではなく、例えば[aBbCcDd]と等価になる場合があります。 のようになります。 ブラケットを従来のように解釈するには 式を使用する場合は、C ロケールを使用するには LC_ALL 環境変数に値Cを設定する。

最後に、特定の名前の付いた文字のクラスは、その中にあらかじめ定義されています。 ブラケット式は、次のようになります。 これらの名前は自明である。 で、それらは [:alnum:], [:alpha:], [:cntrl:], [:digit:] です。 [グラフ:]、[:lower:]、[:print:]、[:punct:]、[:space:]、[:upper:]です。 および[:xdigit:]である。 例えば、[[:alnum:]]は、以下のような文字クラスです。 の数字と文字が含まれる。CロケールおよびASCII 文字セットエンコーディングでは、[0-9A-Za-z]と同じになります。 (注 これらのクラス名の括弧はシンボルの一部である。 を区切る大括弧に加えて、さらに大括弧を含める必要があります。 括弧式)。 ほとんどのメタキャラクタは特別な意味を失います。 ブラケット式の内側では リテラルを含めるには、[ ]内にそれを置きます。 をリストの最初に置く。 同様に、リテラル ^ を含めるには、リストの最初に置きます。 を除いては、どこでもよい。 最後に、リテラル - を含めるには、それを配置します。 を最後にします。