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

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

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

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

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.

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

答え2

明示的な文字列を一致させる唯一の方法は、これを引用することです。

[[ $var =~ 'quux' ]]

文字列に特殊文字(シェルに特殊文字)が含まれていても[ㅏ])
シェルが拡張または解釈せずに[雨]:

$ var='^abcd'
$ [[ $var =~ '^ab' ]] && echo yes || echo no
yes

実際には(シェル)特殊文字を受け入れ、シェルがそれを正規表現として解釈できるようにするには、引用符をオフにする必要があります。

$ var='abcd'
$ [[ $var =~ ^ab ]] && echo yes || echo no
yes

ただし、引用符のない文字列はスペースなどの新しい問題を引き起こします。

$ var='ab cd'
$ [[ $var =~ ^ab cd ]] && echo yes || echo no
bash: syntax error in conditional expression
bash: syntax error near `cd'

この問題を解決するには、特殊文字を引用する必要があります。

$ var='ab cd'
$ [[ $var =~ ^"ab cd" ]] && echo yes || echo no
yes

$ [[ $var =~ ^ab\ cd ]] && echo yes || echo no
yes

他の例:

[[ "a b"  =~  ^a\ b$ ]] && echo yes
[[ "a|b"  =~  ^a\|b$ ]] && echo yes
[[ "a&b"  =~  ^a\&b$ ]] && echo yes

正規表現を変数に保存すると、これらすべての参照問題を回避できます。

$ regex='^a b$'
$ [[ "a b" =~ $regex ]] && echo yes
yes

[ㅏ] シェル特殊文字リスト(| & ; ( ) < > space tab newline)。

[雨] これは本当ですbash バージョン bash-3.2-alpha ベース(「3. Bash の新機能」のタイトルの下):

F.他のパターン一致演算子と同様に、[[コマンドの=~演算子の文字列引数を参照すると、文字列一致が強制されます。


サポートBash FAQの詳細な説明:

E14)正規表現一致条件演算子(=〜)のパターン引数を参照すると、正規表現一致が動作を停止するのはなぜですか?

bash-3.2以前のbashでは、[[コマンドの=〜演算子の正規表現パラメータを参照する効果は指定されていませんでした。その結果、二重引用符で囲まれたパターンパラメータには、特殊パターン文字を引用するためにバックスラッシュが必要です。これは、二重引用符で囲まれた単語拡張によって実行されるバックスラッシュ処理を妨げ、==シェルパターン一致演算子が引用符付き文字を処理する方法と一致しません。

bash-3.2では、シェルは=〜演算子の一重引用符と二重引用符で囲まれた文字列引数から内部的に文字を引用するように変更されました。これは、正規表現処理('.'、'['、'\)に固有の文字の特別な意味を抑制します。 ', '(', ')', '*', '+', '?', '{', '|', '^' および '$') 文字通り一致するように強制します。これは、「==」パターンマッチング演算子がパターン引数の引用部分を処理する方法と一致します。

引用符付き文字列パラメータの処理方法の変更により、いくつかの問題が発生しました。その最大の問題は、パターンパラメータの空白とbash-3.1とbash-3.2の間で引用された文字列の他の処理問題です。 2つの問題は、シェル変数を使用してパターンを保存することで解決できます。 [[コマンドのすべてのオペランドでシェル変数を展開すると単語の区切りが実行されないため、ユーザーは変数を割り当てるときに必要に応じてパターンを引用し、値をスペースを含む単一の文字列に拡張できます。最初の問題は、バックスラッシュや他の引用メカニズムを使用してパターンのスペースをエスケープすることで解決できます。

関連質問:

正規表現で変数を使用する

関連情報