変数名が文字列として格納されている場合、変数値を取得するにはどうすればよいですか?


142

変数名を文字列として持っている場合、bash変数の値を取得するにはどうすればよいですか?

var1="this is the real value"
a="var1"
Do something to get value of var1 just using variable a.

環境:

いくつかのAMI(Amazon Machine Image)があり、各AMIのいくつかのインスタンスを起動したいと思います。起動が完了したらすぐに、AMIタイプに従って各インスタンスをセットアップしたいと思います。AMI内で大量のスクリプトや秘密鍵を焼きたくないので、一般化された起動スクリプトを用意し、それを公にアクセス可能なリンクを使用してS3に配置しました。rc.localに、起動スクリプトをフェッチして実行する小さなコードを入れました。これがAMIにあるすべてです。次に、各AMIは、すべてのAMIに適用可能な共通の構成スクリプトと、それぞれの特別なセットアップスクリプトにアクセスします。これらのスクリプトはプライベートであり、アクセスするには署名付きURLが必要です。

そこで、AMIのインスタンス(my_private_ami_1)を起動するときに、すべてのプライベートスクリプトの署名付きURLを含む、S3に提示されたもう1つのファイルの署名付きURLをキーと値のペアで渡します。

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
起動スクリプトが実行されると、上記のファイルがダウンロードされますsource。次に、そのAMIタイプをチェックし、それ自体に適切なセットアップスクリプトを選択します。

ami\_type=GET AMI TYPE #ex: sets ami\_type to my\_private\_ami\_1
setup\_url=GET THE SETUP FILE URL BASED ON AMI\_TYPE # this is where this problem arises

これで、AMIタイプに関係なくインスタンスを起動できる汎用コードを作成できるようになり、インスタンスが自分で処理できるようになりました。

回答:


257

使用できます${!a}

var1="this is the real value"
a="var1"
echo "${!a}" # outputs 'this is the real value'

これは、間接的なパラメーター展開の例です。

パラメータ展開の基本的な形式は${parameter}です。の値 parameterが置換されます。

の最初の文字がparameter感嘆符(!)の場合、変数の間接参照のレベルが導入されます。Bashは、残りのから形成された変数の値を変数parameterの名前として使用します。次に、この変数が展開され、その値がparameterそれ自体の値ではなく、残りの置換で使用されます。


4
これはOSX bashでは機能しますが、debianでは機能しませんか?debianではBad substitutionエラーになります。
23inhouse 2013

11
@ 23inhouseを使用してスクリプトを実行しています/bin/shか?その場合は、/bin/bash代わりに使用してみてください。Debian Squeeze以降、ではなくのシンボリックリンク/bin/shに変更されました。この特定の構文はサポートされておらず、エラーが出力されます。dashbashdashBad substitution
Phil Ross

8
配列に属する変数名に対してこれを機能させる方法はありますか?
Loupax 2014年

ubuntuとbashで動作します
セルゲイP.別名azure 14

1
@DoronShaiこれはでBashのリファレンスマニュアルに記載さ、間接的なパラメータ展開の一例であるgnu.org/software/bash/manual/html_node/...
フィル・ロス

29
X=foo
Y=X
eval "Z=\$$Y"

Zを「foo」に設定します

eval値を介してコードが誤って実行される可能性があるため、使用には注意してください${Y}。これにより、コードインジェクションによって害が生じる可能性があります。

例えば

Y="\`touch /tmp/eval-is-evil\`"

作成します/tmp/eval-is-evilrm -rf /もちろん、これは一部の場合もあります。


私のしっぽを救ったty
ラフィアン

9

私の検索キーワードを変更し、それを得た:)。

eval a=\$$a
御時間ありがとうございます。


evalの使用には注意が必要${Y}です。これにより、の値を介してコードが誤って実行される可能性があります。ユーザー「anon」の答えに私の追加を参照してください。
try-catch-finally

これが唯一の有効な答えです。それはあなた自身のものであるという皮肉なことです!
Ctrl S

8

私の仲間のzshユーザーにとって、受け入れられた答えと同じことを達成する方法は、以下を使用することです:

${(P)a}

パラメータ名置換と呼ばれます

これにより、パラメーター名の値が追加のパラメーター名として解釈され、その値が適切な場所で使用されます。typesetファミリーのコマンドの1つで設定されたフラグ(特にケース変換)は、この方法で使用されるnameの値には適用されないことに注意してください。

ネストされたパラメーターまたはコマンド置換で使用される場合、その結果は同じ方法でパラメーター名として使用されます。たとえば、「foo = bar」と「bar = baz」がある場合、文字列$ {(P)foo}、$ {(P)$ {foo}}、および$ {(P)$(echo bar) }は 'baz'に展開されます。

同様に、参照自体がネストされている場合、フラグ付きの式は、パラメーター名で直接置き換えられたものとして扱われます。このネストされた置換が複数の単語を含む配列を生成する場合、エラーになります。たとえば、パラメーターassocが連想配列である 'name = assoc'の場合、 '$ {$ {(P)name} [elt]}'は連想添字付き 'elt'の要素を参照します。


0

最近のシェルはすでに配列(さらには連想配列)をサポートしています。ですから、それらを使用し、評価を減らしてください。

var1="this is the real value"
array=("$var1")
# or array[0]="$var1"

次に、それを呼び出したいときに、$ {array [0]}をエコーし​​ます。


コマンドライン引数から文字列を取得した場合、これは機能し$1ますか(例:)?
イエナ2018年

0

回答に基づいて:https://unix.stackexchange.com/a/111627

###############################################################################
# Summary: Returns the value of a variable given it's name as a string.
# Required Positional Argument: 
#   variable_name - The name of the variable to return the value of
# Returns: The value if variable exists; otherwise, empty string ("").
###############################################################################
get_value_of()
{
    variable_name=$1
    variable_value=""
    if set | grep -q "^$variable_name="; then
        eval variable_value="\$$variable_name"
    fi
    echo "$variable_value"
}

test=123
get_value_of test
# 123
test="\$(echo \"something nasty\")"
get_value_of test
# $(echo "something nasty")

0

配列についても同じ問題がありましたが、配列を操作している場合の方法は次のとおりです。

array_name="ARRAY_NAME"
ARRAY_NAME=("Val0" "Val1" "Val2")

ARRAY=$array_name[@]
echo "ARRAY=${ARRAY}"
ARRAY=("${!ARRAY}")
echo "ARRAY=${ARRAY[@]}"
echo "ARRAY[0]=${ARRAY[0]}"
echo "ARRAY[1]=${ARRAY[1]}"
echo "ARRAY[2]=${ARRAY[2]}"

これは出力します:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.