web-dev-qa-db-ja.com

引用符で囲まれた文字列でのコマンド置換とバックスラッシュエスケープ

次のように、内部に円記号エスケープを含む二重引用符で囲まれたコマンド置換について考えてみます。

echo "$(echo '\\')"

\\を出力しますが、バックスラッシュを1つだけ出力すると予想していました。私の考え(これは正しくありません)は、文字列全体を通過し、すべてのバックスラッシュエスケープを置き換え、その後コマンド置換を行うというものでした。明らかに、順序は逆です。

しかし、そうすれば

echo "$(echo '\')$"

\$を出力します。コマンド置換を実行している場合firstで、その文字列のバックスラッシュエスケープを評価すると、\$が組み合わされて最終的に単一の$になる可能性があると予想していました。しかし、そうではありません。

バックスラッシュエスケープはどこで物事の順序に適合しますか?

(この質問のコンテキストは、sedコマンドに挿入するために文字列内の正規表現文字を適切にエスケープするものに取り組んでいるということです。)

2
AmadeusDrZaius

echo $(echo '\\')(つまり、外側の引用符のないバリアント)の出力によって最もよく理解され、結果は_\\_になると思います。重要なのは、コマンド置換エンティティ$(...)が展開されたときに、リテラル文字列バックスラッシュの解釈がないということです。 (これは、文字列にエスケープ文字が格納されている場合も同様です。リテラル文字列として再解釈されることはありません。)

2
Janis

$(…)で区切られたコマンド置換では、括弧内の内容はトップレベルコマンドと同じ方法で解析されます(不均衡な閉じ括弧を含むいくつかのコーナーケースを除く)。括弧内は通常のシェルスニペットであり、追加のバックスラッシュ拡張は行われていません。

コマンド_echo '\\'_は、2つのバックスラッシュと改行の3文字を出力します(バックスラッシュ展開を行わないechoコマンドを想定)。したがって、コマンド置換$(echo '\\')の結果は、2文字の文字列_\\_になります(最後の改行は削除され、コマンド置換は常にこれを行います)。二重引用符内でコマンド置換を使用したため、他の展開は実行されません。結果のWord部分は_\\_です。

echo "$(echo '\')$"では、コマンド置換により1つの円記号が出力されます。 echoへの引数への寄与は、文字列_\_です。次の_$_の後には、パラメーター名を開始できない文字が続くため、それ自体に展開されます。したがって、echoの引数は、2文字の文字列_\$_です。二重引用符で囲まれた文字列はこれ以上展開されません。円記号が特殊文字として解釈される原因となるものはありません(echoコマンドの一部のフレーバーを除く)。

シェルのマニュアルやその他のドキュメントで、さまざまな程度の(読みにくい)読みやすさを備えた完全な拡張ルールを調べることができます。 POSIX仕様 標準が進むにつれてそれほど悪くはありません(かすかな賞賛)。

P.S. `sed`置換に補間された文字列がすべてのメタ文字をエスケープするようにする方法

それは引用ともっと関係があります、

$ echo '\'
\
$ echo '\\'
\\
$ echo "\\"
\

一重引用符を使用すると、引用符の間にあるものはすべてエコーされます。二重引用符を使用すると、シェルは内部を調べて処理を行います。

1
kjohri