変数の呼び出しに引用符で囲まれたコマンド置換は使用できません。

変数の呼び出しに引用符で囲まれたコマンド置換は使用できません。

説明する:

variable="Something that it holds"

それから echo "$variable"出力されます: それが含んでいる内容

しかし、私もそうだとしましょう。

var2="variable";  
echo "\$$(echo $var2)"

$variable
代わりに:何が含まれているのかを出力します。

ここでUnixのどの機能が機能しているかを教えてくれる人はいますか?

答え1

variable="Something"
var2="variable";
echo "\$$(echo $var2)"

最後の行では"\$$(echo $var2)"→→$variableを期待していますSomething。これを行うには、シェルがパラメータ拡張を2回実行する必要があります。そうではありませんが、単に$(echo $var2)接頭辞付きのコマンド置換結果を印刷します$

原則として、評価する欲しいものを手に入れるのを手伝ってください。シェルが最初のステップ"\$$(echo $var2)"→を実行した後、$variableevalは2番目のステップ$variable→を実行しますSomething

$ eval echo "\$$(echo $var2)"
Something

上記のコマンドは特定のケースでは問題ありませんが、まだ正しい引用符がありません。printf銃愛を受けるecho

$ eval 'printf "%s\n" "${'"$var2"'}"'
Something

ただし、evalは信頼できないデータによってセキュリティ上の問題を引き起こす可能性があります。推定 var2="variable;rm importantFile"。この場合、評価に合格します。

echo $variable;rm importantFile

シェルにimportantFile追加すると幸せに削除されます。

一部のシェル(Bash、ksh、Zshなど)では、次のものも使用できます。間接的な。 Bashの間接拡張構文は次のとおりです。

$ echo "${!var2}"
Something

var2="variable;rm importantFile"もう問題ではありませんが、var2='a[$(rm importantFile)]'まだ問題です。

間接参照の詳細バッシュマニュアル。

パラメータの最初の文字が感嘆符(!)で、パラメータがnamerefでない場合は、間接参照レベルが導入されます。 Bash は残りの引数を拡張することによって形成された値を新しい引数として使用し、その値は元の引数の拡張ではなく残りの拡張に使用されます。

答え2

アンチパターン(*)の臭いがします。多くのシェルには文字列インデックスの配列/辞書があります。 in ksh93(この構文のソース)bashまたはzsh

typeset -A dictionary
x="keyX"
y="keyY"
dictionary[keyX]="valueX"
dictionary[$y]="valueY"

printf '%s\n' "${dictionary[$x]}"
printf '%s\n' "${dictionary[keyY]}"

(*) Linux自体とは何の関係もありません。変数の変数名は非常に一般的な変数です。「アンチパターン」、してはいけないこと、そしてそれが必要だと思えばデザインに何か問題があるのです(XYの問題)?変数で変数名を使用するほとんどは、辞書(存在する場合)に置き換えるのが最善です。

答え3

あなたが観察するもの標準行動の一つPOSIXshell: 一般的に言えば、

  1. 入力を読んでください。

  2. 入力をトークン(単語と演算子)で分割します。トークン認識);

    • この段階で、次の問題が発生するたびに引用しない $(または`)は、拡張タイプと拡張するタグを繰り返し決定し、必要なすべての入力を読み取ります。
  3. 入力を単純コマンドと複合コマンドに解析します。

  4. 様々な実行拡大する各コマンドの他の部分で (それぞれ) コマンドと引数として扱われるパス名とフィールドのリストを生成します。

  5. リダイレクトを実行し、パラメータリストからリダイレクト演算子とそのオペランドを削除します。

  6. 関数、組み込み実行可能ファイル、またはスクリプトを実行します。

  7. (オプション)コマンドが完了して終了ステータスが収集されるのを待ちます。

構文解析すると、echo "\$$(echo $var2)"シェルは2つの拡張(ステップ2)、つまり二重引用符で囲まれたコマンド置換と引用符なしのパラメータ$(echo $var2)拡張を検出します$var2。エスケープされた$inは、\$二重引用符がドル\記号として機能するため、文字通りドル記号として扱われます。エスケープ文字フォローするとき$

以降のステップでは、拡張された検出は発生しません。具体的には、ステップ4("\$$(echo $var2)"→→→ )で実行された拡張結果は、"\$$(echo variable)"拡張トリガ文字を検出するために解析されなくなりました。"\$variable"$variable

さらに、この$記号はパラメータ拡張の文脈で変数名をその内容に置き換えるために使用されますが、汎用には設計されていません。逆参照演算子

存在する標準パラメータ拡張、最も単純な形式は次のとおりです。${parameter}、これparameter仕様では、変数名、位置パラメータ、または特殊パラメータのみを受け入れます(参照:「パラメータ」の定義)。厳密に言えば、パラメータ拡張はネストできません。拡張式は、次の場合にのみ許可されます。word様々な${parameter<symbols>[word]}形態)。

以下を使用して簡単に確認できます。Zシェルを除く${${foo}}は有効な式ではなく、シェル$$のPIDに展開されます。したがって の$foo値に拡張されfoo$$fooシェルの PID とリテラル "foo" の連結に拡張され、$$$fooの PID 連結に拡張されます。シェルとfoo、...)の値。

答え4

間接変数の拡張に加えて、bash(バージョン4.3以降)で次のものを使用することもできます。名前参照

declare -n var2="variable"  # "var2" is a _reference_ to "variable"

variable="Something"
echo "$var2"     # => Something

variable="something else"
echo "$var2"     # => something else

unset variable
echo "$var2"     # => ""

これがどのように実装されるかはわかりませんが、興味深い情報があります。間接参照を使用すると、namerefが参照する内容を見つけることができます。

echo ${!var2}    # => variable

関連情報