コマンドの置き換えと二重引用符:結果が異なるのはなぜですか?

コマンドの置き換えと二重引用符:結果が異なるのはなぜですか?

以下は、バックティックと$()がどのように異なる動作をするかを示す例です。

$ echo "$(echo \"test\")"
"test"
$ echo "`echo \"test\"`"
test

私の理解はこれだからです。「バックティック内のバックスラッシュ(\)は不明瞭な方法で処理されます。」

しかし、これは別の話のようです。なぜなら、外側の二重引用符を削除すると結果が似ているからです。

$ echo $(echo \"test\")
"test"
$ echo `echo \"test\"`
"test"

誰かがこれがどのように機能するのか、そして「echo \"test\"`"が二重引用符を削除する理由を説明できますか?

答え1

あなたは正しいです。この場合は別の話です。

解決策はまだ残っています同じリンクしかし、2番目のポイントは次のとおりです。

  • $() 内にネストされた参照がはるかに便利です。

    [...]

    `...`は移植性のために内部引用符の周りにバックスラッシュが必要です。

したがって、

echo "`echo \"test\"`"

次のとおりではありません。

echo "$(echo \"test\")"

しかし、これは:

echo "$(echo "test")"

これを以下と比較する必要があります。

echo "`echo \\"test\\"`"

答え2

バックティックを使用したコマンド置換が引用符を削除する理由は、実装方法によるものです。

  • バックティック内のテキストは、最後の実行前に語彙アナライザを介して渡されます。

    これは、1つの参照レベルを占める語彙アナライザによる最初の伝達結果が文字列として保持され、最終実行中にパーサ全体を再度通過するために発生する。したがって、逆引用符ベースのコマンド置換は、2つのレベルの引用を取り除きます。

  • $(...)最終実行中にパーサー全体を通過する前に、その中のテキストは変更されていません。

    • これはkshロギングによって達成されます。テキストを入力してください')̈́'パーサが一致するクロージャを解析する副作用として$(

    • これは、パーサーが一致するクロージャーを構文解析し、関連する等価物を再構成しながらパーサーが出力したバイナリ構文ツリーを記録することによってbosh達成されます。mksh')̈́'$(元の入力実行された最終バイナリツリー。

    したがって、$(...)コマンドベースの置換は単一の参照レベルのみを削除します(これは通常のコマンド実行でも発生します)。

この実装により、バックティックベースの命令置換は、grepパターンがその命令の一部である場合、特に予期しない動作を引き起こす可能性がある。そのため、$(...)最初に使用することをお勧めします。

答え3

その理由は、(二重)引用符付き文字列で発生することです。

シェルパーサーは、1つ(引用符なし)が見つかると、次"(引用符なし)で終わる文字列全体を"引用符で宣言します。引用符付き文字列内で最大バックスラッシュいいえ削除されました。国連引用符文字列ではバックスラッシュが削除されます。

~からPOSIX(ほとんどのバックスラッシュ除去):

<backslash>引用符なしのAは、次の文字のリテラル値を保持する必要があります。

これは実際に表示されます(set -xは解析後にシェルが実行することを示します)。

$ ksh -c 'set -x; echo test\h\jtest; set +x'
+ echo testhjtest
testhjtest

引用符のないバックスラッシュは削除されます。しかし、引用はありません:

$ ksh -c 'set -x; echo "test\h\jtest"; set +x'
+ echo 'test\h\jtest'
test\h\jtest

~からPOSIX二重引用符:

<backslash>エスケープ文字としての特別な意味は、次のいずれかの文字が続く場合にのみ保持する必要があります(エスケープ文字(バックスラッシュ)を参照)。

だからこそバックスラッシュは引用符付き文字列から削除されます。

$   `   "   \   <newline>

例:

$ ksh -c 'set -x; echo "test\"\h\j\"test"; set +x'
+ echo 'test"\h\j"test'
test"\h\j"test

見つかった最初の文字が(二重)引用符の場合、これが発生します。

最初の逆引用符()が見つかる`と、解析規則が異なります。まず、文字列は引用符なしで始まります(内部二重引用符は引用符を始めることができます)。一つ範囲を引用してください(終了()まで)。`下の最初の行の一重引用符に注意してください。"

$ set -x; echo `echo \"\`echo \\"test\\" \`\"`; set +x
+++ echo '"test"'
++ echo '""test""'
+ echo '""test""'
""test""
+ set +x

$(…)代わりにAが始まります。新しい毎回範囲を参照してください。

$ set -x; echo $(echo \"$(echo \\"test\\" )\"); set +x
+++ echo '\test\'
++ echo '"\test\"'
+ echo '"\test\"'
"\test\"
+ set +x

結果は全く異なります。

関連情報