Bash sed は二重ドル記号 $$ 拡張正規表現を置き換えます。

Bash sed は二重ドル記号 $$ 拡張正規表現を置き換えます。

このコマンドは次のとおりです。

echo '$$foo=bar' | sed -E "s/(\$\$foo=).*/\1$(echo hello)/"

出力:

$$foo=bar

sed'引用符を一重引用符に変更し、コマンドを二重引用符で囲むと、次のようになります。

echo '$$foo=bar' | sed -E 's/(\$\$foo=).*/\1'"$(echo hello)"'/'

希望の結果が出力されます。

$$foo=hello

だから私は明白なものを見逃していない限り、拡張正規表現と引用符に問題があると思います。

  1. sedコマンド置換()で一重引用符と二重引用符を連結するのは良い習慣ですかsed 's/foo/'"$(command)"'/'

  2. sed拡張正規表現を使用してダブルドル記号をエスケープする方法は?

答え1

POSIXで言うことがあります$基本正規表現と拡張正規表現の解釈方法の違いは次のとおりです。

基本正規表現(BRE):

<dollar-sign>()がBRE全体の最後の文字として使用される場合は、$アンカーポイントにする必要があります。子式の最後の文字として使用されている場合は、実装時にaを<dollar-sign>アンカーとして扱うことができます。<dollar-sign>式(またはオプションのサブ式)は、一致する文字列の末尾に固定する必要があります。<dollar-sign>つまり、最後の文字の後の文字列の終わりと一致する必要があります。

拡張正規表現(ERE):

<dollar-sign>()括弧式の外側は、閉じた$式またはサブ式を文字列の末尾に固定します。これらの式またはサブ式は、文字列の最後の文字で終わるシーケンスのみを一致させることができます。たとえば、EREef$とEREは文字列内で一致します(ef$)が、文字列内では失敗し、EREは機能しますが一致しません。ブロック式の一致が最後の文字で終わるからです。efabcdefcdefabe$ffe$

結論:BREでは、$文字は式または子式の最後の文字でない限り、それ自体が一致します(この場合(子)表現式を行の末尾に固定します)。 ERE では、$役割は常に行末に固定されます。

使用するとき

sed -E "s/(\$\$foo=).*/\1$(echo hello)/"

あなたのERE(使用するように-E)は($$foo=).*次のとおりです。この式はいいえe$f一致します(上記のPOSIXテキストにも同様の例が含まれています)。

注文

sed "s/\$\$foo/\$\$hello/"

文字が式の末尾にないため、BREを使用して$$fooリテラル文字列を一致させます。$$foo$

$拡張正規表現で単一の文字を一致させるには、\$またはを使用します[$]。二重引用符で囲まれた文字列でシェルをエスケープするには、\\\$(エスケープされたバックスラッシュの後にエスケープされたドル記号)またはを[\$]使用します。

sed -E "s/(\\\$\\\$foo=).*/\1$(echo hello)/"

または

sed -E "s/([\$][\$]foo=).*/\1$(echo hello)/"

\1(バックスラッシュは後ろにドル記号、バックティック、二重引用符、他のバックスラッシュ、または改行文字が続く場合は二重引用符で囲まれた文字列でエスケープ文字としてのみ機能するため、バックスラッシュはエスケープする必要はありません\1。意味1;ここを参照してください)。

短い答え:

  1. 一重引用符が必要なビットを一重引用符で囲んだり(シェル拡張を含む二重引用符文字列に関連付ける)、単一二重引用符文字列にエスケープする必要があるものをエスケープできます。それは味の問題です。挿入された文字列を完全に制御できない場合、これはコード挿入の脆弱性であるため、式でコマンド置換を使用する方が心配です。

  2. \\\$または[\$]二重引用符で囲まれた文字列です。\$または[$]一重引用符文字列として。

関連情報