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

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

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

#!/bin/sh
# 変数 VALに値が入力されている
VAL="test"

# 変数 EVAL_VALに、変数名である「VAL」という文字列を入力
EVAL_VAL="VAL"

# 変数 EVAL_VALを呼び出す
echo $EVAL_VAL

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

$ 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の書き方を以下のように書き換えたらどうなるだろうか。

#!/bin/sh
# 変数 VARに値が入力されている
VAR="test"

# 変数 EVAL_VARに、変数名である「VAR」という文字列を入力
EVAL_VAR="VAR"

# 変数 EVAL_VARを呼び出す
# echo $EVAL_VAR
eval echo '$'$EVAL_VAL

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

$ 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で呼び出しただけでは一区切り目の値しか出力されない。
だからといって、単純に配列番号を入れると動作しないようだ。そのため、以下のような記述をすると良いだろう。

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

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

#!/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]}'

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

$ 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

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