シェル変数に正規表現を格納してシェル固有の文字を引用する問題を回避するには?

シェル変数に正規表現を格納してシェル固有の文字を引用する問題を回避するには?

~からバッシュマニュアル

シェル変数に正規表現を格納することは、シェル固有の文字を引用するときに問題を回避する便利な方法であることがよくあります。場合によっては、引用符を使用せずに正規表現を文字通り指定したり、シェルの引用符の削除に注意しながら、正規表現で使用されている引用符を追跡することは困難です。シェル変数を使用してパターンを保存すると、これらの問題を軽減できます。たとえば、次は同じです。

pattern='[[:space:]]*(a)?b'
[[ $line =~ $pattern ]]

そして

[[ $line =~ [[:space:]]*(a)?b ]]

正規表現構文で特殊文字を一致させるには、特殊文字を引用符で囲んで特殊意味を削除する必要があります。つまりxxx.txt、パターン内では.文字列内のすべての文字(通常の正規表現の意味)と一致しますが、パターン内では"xxx.txt"リテラルのみを一致できます.。シェルプログラマーはバックスラッシュに特別な注意を払う必要があります。これは、シェルと正規表現の両方がバックスラッシュを使用して次の文字の特別な意味を削除するためです。次の2つのコマンドセットは同じではありません。

pattern='\.'

[[ . =~ $pattern ]]
[[ . =~ \. ]]

[[ . =~ "$pattern" ]]
[[ . =~ '\.' ]]

最初の2つの一致は成功しますが、2番目の2つの一致は失敗します。なぜなら、後者の2つの一致ではバックスラッシュが一致するパターンの一部になるからです。最初の2つの例では、バックスラッシュは特別な意味を取り除くので、.リテラルは.一致します。.たとえば、最初の例の文字列がない場合、パターンの引用符が単一の文字と一致するという特別な意味を失うaため、パターンは一致しません。.

シェル変数に正規表現を格納することは、どのようにシェル固有の文字を引用するときに問題を回避するための便利な方法になりますか?

与えられた例はこれを説明していないようです。与えられた例では、あるメソッドの正規表現リテラルとpattern他のメソッドのシェル変数は同じ値を持ちます。

ありがとうございます。

ベストアンサー1

[[ ... ]]トークン化が正規表現と衝突します(詳細はあなたのフォローアップ質問に対する私の答え)と\シェル引用演算子と正規表現演算子(bash内の2つの間にわずかな干渉がある)でオーバーロードされ、競合の明白な理由がない場合でもルールが混乱する可能性があります。

(可能なすべての入力に対して)試してみて、特定のバージョンが何をするのか誰が知っていますかbash

[[ $a = a|b ]]
[[ $a =~ a|b ]]
[[ $a =~ a&b ]]
[[ $a =~ (a|b) ]]
[[ $a =~ ([)}]*) ]]
[[ $a =~ [/\(] ]]
[[ $a =~ \s+ ]]
[[ $a =~ ( ) ]]
[[ $a =~ [ ] ]]
[[ $a =~ ([ ]) ]]

bash 3.2以降、正規表現を引用するとbash 3.1の互換性が有効になっていない場合、正規表現を引用するとRE演算子の特別な意味が取り除かれるため、正規表現を引用できません。例えば、

[[ $a =~ 'a|b' ]]

$aテキストのみが含まれている場合は一致しますa|b

正規表現を変数に保存すると、これらすべての問題を回避でき、コードが互換性になりますksh93zshPOSIX EREに制限されている場合)。

regexp='a|b'
[[ $a =~ $regexp ]] # $regexp should *not* be quoted.

シェルコマンドはあいまいさなしで解析/トークン化され、使用された正規表現は変換なしで変数に格納された正規表現です。

おすすめ記事