はじめに
タイトルいったい何のことか伝わらないと思うので。
いわゆる2次元配列っぽいことをしたいというか、要素数の異なる複数のテーブルを多重ループで回す感じ。
2次元配列が近いと思って調べたけど、自分のやりたいこととうまく合致しないかな。と。
やりたいこと
例えば、複数の環境と対象としてテストプログラムを実行したいが、環境毎に実行するプログラムが異なる。
環境と環境毎のテストプログラムのテーブルをそれぞれもってて、それを組み合わせてループさせたい。
#include <cstdio> #include <vector> int main() { enum { Env1, Env2, Env3, Env_Max, }; std::vector<const char*> env1_test {"testA", "testB", "testC"}; std::vector<const char*> env2_test {"testD"}; std::vector<const char*> env3_test {"testA", "testB", "testC", "testD"}; std::vector<std::vector<const char*>> table { {env1_test}, {env2_test}, {env3_test}, }; for (auto i = 0; i < Env_Max; ++i) { for (auto elem : table[i]) { std::printf("Env[%d]:%s\n", i, elem); } } return 0; }
実行結果
Env[0]:testA Env[0]:testB Env[0]:testC Env[1]:testD Env[2]:testA Env[2]:testB Env[2]:testC Env[2]:testD
環境毎のテストプログラムの数が異なるのがポイント。
やったこと
bashスクリプトでは多重配列が無い(はず?)なので、このようなケースは意外と難しい。
ほとんど型の概念がなく、文字列処理としての側面が強いので、実行時に変数名を合成して複数の配列を組み合わせることにした。
#!/bin/bash readonly -a Env1_test=( testA testB testC ) readonly -a Env2_test=( testD ) readonly -a Env3_test=( testA testB testC testD ) readonly -a Environments=( Env1 Env2 Env3 ) execute() { local env=$1 local test=$2 echo ${env} ${test} } execute_all() { for env in ${Environments[@]} ; do local -n tests=${env}_test for t in ${tests[@]} ; do execute ${env} ${t} done done } execute_all
実行結果
$ ./test.sh Env1 testA Env1 testB Env1 testC Env2 testD Env3 testA Env3 testB Env3 testC Env3 testD
execute_all
の「local -n tests=${env}_test」の行で変数名を合成している。
ここではEnvironments
配列の内容であるEnvX
と固定の文字列_test
を合成してEnvX_test
という変数名を作成して、
その中の要素にループでアクセスしている。-n
がポイントで、変数を名前参照とすることで、
展開後の変数と文字列を組み合わせて、別に実体のある変数の参照をローカル変数のtests
に格納している。
これをしないと、実体が空のEnvX_testがtests
に格納されるので意図した動きにならない。
まとめ
名前参照を使うと意外と便利なことができる。 ただしやりすぎると破綻する。