シェルスクリプトでevalコマンドを用いた変数の2重展開

シェルスクリプトを作成する際、事前に定めた変数名をスクリプト内で他の変数に代入し、それを展開・利用したいシチュエーションもあるだろう。
そんな時は、evalコマンドを用いて変数を2重展開することで対応可能だ。

例えば、以下のようなスクリプトを作成したとする。

bash
#!/bin/sh # 変数 VALに値が入力されている VAL="test" # 変数 EVAL_VALに、変数名である「VAL」という文字列を入力 EVAL_VAL="VAL" # 変数 EVAL_VALを呼び出す echo $EVAL_VAL

これをそのまま実行した場合、当然ながら出力される値は「VAL」となる。

shell
$ cat test_eval_1.sh #!/bin/sh # 変数 VALに値が入力されている VAL="test" # 変数 EVAL_VALに、変数名である「VAL」という文字列を入力 EVAL_VAL="VAL" # 変数 EVAL_VALを呼び出す echo $EVAL_VAL $ $ $ sh -x test_eval_1.sh + VAL=test + EVAL_VAL=VAL + echo VAL VAL

では、echoの書き方を以下のように書き換えたらどうなるだろうか。

bash
#!/bin/sh # 変数 VARに値が入力されている VAR="test" # 変数 EVAL_VARに、変数名である「VAR」という文字列を入力 EVAL_VAR="VAR" # 変数 EVAL_VARを呼び出す # echo $EVAL_VAR eval echo '$'$EVAL_VAL

このように、evalコマンドを利用すると、変数の2重展開が可能となる。

shell
$ cat test_eval_1.sh #!/bin/sh # 変数 VALに値が入力されている VAL="test" # 変数 EVAL_VALに、変数名である「VAL」という文字列を入力 EVAL_VAL="VAL" # 変数 EVAL_VALを呼び出す # echo $EVAL_VAL eval echo '$'$EVAL_VAL $ $ $ sh -x test_eval_1.sh + VAL=test + EVAL_VAL=VAL + eval echo '$VAL' ++ echo test test

echoの後のevalで変数を展開しているため、その際に使用する「$」がechoで解釈されないように、シングルクォーテーションで囲む必要がある点に注意。

変数が配列の場合

利用したい変数が配列の場合、ただevalで呼び出しただけでは一区切り目の値しか出力されない。
だからといって、単純に配列番号を入れると動作しないようだ。そのため、以下のような記述をすると良いだろう。

bash
eval echo '${'$変数名'[配列番号]}'

実際に動作させたスクリプトが以下。

bash
#!/bin/sh # 変数「VAL」を配列として値を代入していく VAL[0]="line 1" VAL[1]="line 2" VAL[2]="line 3" # 変数 EVAL_VALに、変数名である「VAL」という文字列を入力 EVAL_VAL="VAL" # 変数 EVAL_VALを呼び出す eval echo '$'$EVAL_VAL # 変数 EVAL_VALを配列として全行呼び出す eval echo '${'$EVAL_VAL'[@]}' # 変数 EVAL_VALを配列として[1]を呼び出す eval echo '${'$EVAL_VAL'[1]}'

実際の実行結果がこちら。

shell
$ cat test_eval_2.sh #!/bin/sh # 変数「VAL」を配列として値を代入していく VAL[0]="line 1" VAL[1]="line 2" VAL[2]="line 3" # 変数 EVAL_VALに、変数名である「VAL」という文字列を入力 EVAL_VAL="VAL" # 変数 EVAL_VALを呼び出す eval echo '$'$EVAL_VAL # 変数 EVAL_VALを配列として全行呼び出す eval echo '${'$EVAL_VAL'[@]}' # 変数 EVAL_VALを配列として[1]を呼び出す eval echo '${'$EVAL_VAL'[1]}' $ $ $ sh -x test_eval_2.sh + VAL[0]='line 1' + VAL[1]='line 2' + VAL[2]='line 3' + EVAL_VAL=VAL + eval echo '$VAL' ++ echo line 1 line 1 + eval echo '${VAL[@]}' ++ echo line 1 line 2 line 3 line 1 line 2 line 3 + eval echo '${VAL[1]}' ++ echo line 2 line 2

無事、配列でも利用できることが分かった。