web-dev-qa-db-ja.com

マッチ式に正規表現リテラルを書く方法は?

この質問は、bashの一致表現で正規表現literalsを記述する適切な方法についてです。

Zshでは、予想通り、以下の一致が成功します。

% [[ ' 123 ' =~ '^ [0-9]+ $' ]]; echo $?
0

バッシュではそうではありません:

$ [[ ' 123 ' =~ '^ [0-9]+ $' ]]; echo $?
1

私はこの試合がbashで成功することを知っています

$ ( regexp='^ [0-9]+ $'; [[ ' 123 ' =~ $regexp ]]; echo $? )
0

...しかし、正規表現を中間変数に割り当てる必要があります。


私の質問は次のとおりです。bashの一致表現で任意の正規表現literalをどのように記述しますか?

6
kjo

Bashのリファレンスマニュアル .2.4.2条件付き構成体 で推奨されているように、変数に入れるのが最善です。

シェル変数に正規表現を格納することは、多くの場合、シェルに特有の文字の引用に関する問題を回避するのに役立つ方法です。引用符を使用せずに文字どおりに正規表現を指定したり、シェルの引用の削除に注意しながら正規表現で使用されている引用を追跡したりするのは難しい場合があります。シェル変数を使用してパターンを格納すると、これらの問題が減少します。

ただし、bash拡張テストの内部に直接書き込むには、引用符を削除してスペースをエスケープする必要があります。

$ [[ ' 123 ' =~ ^\ [0-9]+\ $ ]]; echo $?
0
8
jesse_b

Bashでは、標準的な答えは次のとおりです。変数を使用

$ reg='^ [0-9]+ $'
$ [[ ' 123 ' =~ $reg ]]; echo $?

これは、スペース、バックスラッシュ、および他の多くのものに対して機能します。

$ reg='^ 12\3 $'
$ [[ ' 12\3 ' =~ $reg ]]; echo $?
0

literalとして記述したい場合は、(慎重に)を引用符で囲む必要があります。
リテラルである必要があるpartsを引用符で囲み、正規表現として解釈する必要がある部分は引用符で囲まないでおく必要があります。スペースは引用が必要です。ここではbackslahを使用しています:

$ [[ ' 123 ' =~ ^\ [0-9]+\ $ ]]; echo $?
0

そして、ここでは二重引用符を使用しています:

$ [[ ' 123 ' =~ ^" "[0-9]+" "$ ]]; echo $?

しかし、その「引用」はバックスラッシュのようなもので本当に厄介になります:

$ [[ ' 12\3 ' =~ ^" "[0-9]+"\\"[0-9]+" "$ ]]; echo $?
0

よりシンプルで安全:

$ reg='^ [0-9]+\\[0-9]+ $'
$ [[ ' 12\3 ' =~ $reg ]]; echo $?
0

そして、いいえ、それを行うためにサブシェルは必要ありません(質問の括弧)。

$ reg='^ [0-9]+\\[0-9]+ $'; [[ ' 12\3 ' =~ $reg ]]; echo $?

はい、それは迷惑に見えるかもしれません。そして、はい、あなたが提示したコマンドはたまたまzshで機能します:

$ [[ ' 123 ' =~ '^ [0-9]+ $' ]]; echo $?
0

ただし、引用は常に問題です(どのシェルでも)、バックスラッシュはどうなりますか?:

% [[ ' 12\3 ' =~ ' 12\3 ' ]]; echo $?
zsh: failed to compile regex: Invalid back reference
1


% [[ ' 12\3 ' =~ '^ [0-9]+\\3 $' ]]; echo $?
0

それを倍増!それは正確ではありません:literal

3
Isaac