以下の投稿、根本的な間違いがあったのであとで直します。(shと思ってたものが、実はbashだったとは、、)
目的
必要に迫られてシェルスクリプトを書くわけですが、どうしてもコマンドの羅列になってしまいがちです。汎用のプログラミング言語並みとはいかなくても少し改善できるアイデアのようなものをメモしていきます。
関数の自動呼出し
declareコマンドで現在定義されている変数名を取得ことができます。-Fオプションを付ければ関数名の一覧が取得できるのでevalと組み合わせれば関数を片っぱしから実行することが可能です。
コード
#!/bin/sh
func_1(){ echo "func_1"; }
func_2(){ echo "func_2"; }
func_3(){ echo "func_3"; }
auto_exec()
{
for func in `declare -F|awk '{print $3}'|grep ^func_`
do
eval $func
done
}
auto_exec
実行結果
[sample@hostname ~]$ ./auto_exce_func.sh
func_1
func_2
func_3
[sample@hostname ~]$
説明
auto_exec関数でdeclare -Fコマンドで定義されている関数名を全て取得し、func_で始まる関数を呼び出しています。ただし、ここでは各関数はパラメータなしという前提です。(シェルスクリプトには関数の型という概念がないので、パラメータの数や型を取得することができません。ただし、evalで引数を渡せないわけではないので、関数名に規則を持たせる等で引数つきの関数を呼びわけることは可能です。)
応用
関数を片っぱしから全て呼び出したくなる場面の身近な例としては、テストの自動実行というのがあるかと思います。他の言語と同様にシェルスクリプトにも単体テスト自動実行のためのライブラリ(リンク:shunit2)はありますが、ここでは簡易な実装をしてみましょう。
コード
#!/bin/sh
test_normal_1()
{
local TEST_CASE="normal 1"
do_test echo "aaa"
}
test_error_1()
{
local TEST_CASE="error 1"
do_test xxyyzz "aaa"
}
#
# 以下はテスト実行のための関数
do_test()
{
local STDOUT=/tmp/stdout.$$
local STDERR=/tmp/stderr.$$
echo ========================
echo テストケース:${TEST_CASE^^}
echo 実行:${*:1}
eval ${*:1} >$STDOUT 2>$STDERR
local RC=$?
echo 戻り値 :$RC
echo 標準出力 :"`cat $STDOUT`"
echo 標準エラー出力 :"`cat $STDERR`"
rm $STDOUT $STDERR 2>/dev/null
}
auto_exec()
{
for func in `declare -F|awk '{print $3}'|grep ^test_|sort`
do
eval $func
done
}
auto_exec
実行結果
[sample@hostname ~]$ ./auto_test.sh
========================
テストケース:ERROR 1
実行:xxyyzz aaa
戻り値 :127
標準出力 :
標準エラー出力 :./auto_test.sh: line 25: xxyyzz: command not found
========================
テストケース:NORMAL 1
実行:echo aaa
戻り値 :0
標準出力 :aaa
標準エラー出力 :
[sample@hostname ~]$
説明
関数auto_execからtest_という名前で始まる関数を順番に呼び出します。各関数内ではテストケース名を設定して、テスト実行用の関数do_testを使用して目的となるコマンド(この場合ではecho "aaa"やxxyyzz "aaa")を呼出し、do_test内で実行結果を表示しています。
ここではシンプルな例ですが、関数の実行結果の期待値と実際の結果を比較することも難しくありません。開発したシェルスクリプトをテストするためのスクリプトを作ってCIツールに組み込むことも可能です。