Bashシェルスクリプトで変数の値を変数名として別の変数を参照する方法

2022-10-16Bash,Linux

はじめに

Bash で変数の値を使って、別の変数を参照するにはどう書けばよいでしょう?

少々説明がくどいですが、PHP や他の言語では普通にできるコードを書けるか?というお話です。

実際に PHP で書く場合と Bash で書く場合を見ていきます。

検証環境

$ uname -moi
x86_64 MacBookPro11,4 Darwin

$ bash -version | head -n 1
GNU bash, バージョン 5.0.11(1)-release (x86_64-apple-darwin18.6.0)

PHP のコードサンプル

以下のように $var1 , $var2 , $var3 の 3 つの変数を、ループを使って参照する場合には以下のようなコードで実現できます。

<?php

$var1 = '111';
$var2 = '222';
$var3 = '333';

for ($i = 1; $i <= 3; ++$i) {
    $varName = "var${i}";
    echo "$i = ${$varName}" . PHP_EOL;
}
$ php test.php
1 = 111
2 = 222
3 = 333

Bash のコードサンプル

方法は 2 つあります。

1. 変数名の前に ! を記述する

先の PHP のサンプルコードと同じように、 var1 , var2 , var3 の 3 つの変数を、ループを使って参照する場合には以下のようなコードで実現できます。

ポイントは ! を付与する点ですね。

通常の変数参照は ${VAR} となりますが、 変数 VAR の値を変数名として参照する場合${!VAR} のように記述します。

#!/usr/bin/env bash

var1="111"
var2="222"
var3="333"

for ((i = 1; i <= 3; i++)); do
  var_name="var${i}"
  echo "var${i} = ${!var_name}"
done
$ bash test.sh
var1 = 111
var2 = 222
var3 = 333

2. eval コマンドを利用する

eval コマンドを使って実現する方法もあります。
先のコードよりも周りくどい書き方となってしまいますが、 Bash が利用できない環境 についてはこの方法でしか実現することができません。

一度変数展開した文字列を作成し、その後 eval コマンドに渡して再度変数展開を行います。

#!/usr/bin/env bash

var1="111"
var2="222"
var3="333"

for i in $(seq 1 3); do
  var_name="var${i}"

  # どんなコマンドが実行されるのかな?
  echo eval "echo \"var${i} = \${${var_name}}\""

  # 実際にコマンドを実行してみる
  eval "echo \"var${i} = \${${var_name}}\""

  # 実際にコマンドを実行してみる
  eval "echo \"\${${var_name}}\""

  # 値だけが欲しい場合は以下のように記述する
  eval "echo \"\${${var_name}}\""

  # 変数に代入する場合は以下のように記述する
  X=$(eval "echo \"\${${var_name}}\"")
  echo $X
done
$ bash test.sh
eval echo "var1 = ${var1}"
var1 = 111
111
111
111
eval echo "var2 = ${var2}"
var2 = 222
222
222
222
eval echo "var3 = ${var3}"
var3 = 333
333
333
333

ひとこと

なかなか利用することはないです。
僕自身も今回初めて記述しました。

多用するとコードも読みにくくなりますしね。

2022-10-16Bash,Linux