Help us understand the problem. What is going on with this article?

シェルスクリプトで黒魔術もどき(その1)関数の自動呼出し

More than 3 years have passed since last update.

以下の投稿、根本的な間違いがあったのであとで直します。(shと思ってたものが、実はbashだったとは、、)

目的

必要に迫られてシェルスクリプトを書くわけですが、どうしてもコマンドの羅列になってしまいがちです。汎用のプログラミング言語並みとはいかなくても少し改善できるアイデアのようなものをメモしていきます。

関数の自動呼出し

declareコマンドで現在定義されている変数名を取得ことができます。-Fオプションを付ければ関数名の一覧が取得できるのでevalと組み合わせれば関数を片っぱしから実行することが可能です。

コード

auto_exec_function.sh
#!/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)はありますが、ここでは簡易な実装をしてみましょう。

コード

auto_test.sh
#!/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ツールに組み込むことも可能です。

tesujiro
さすらいの開発者。 海外旅行しながらリモート開発するのが理想だが、実際はSI現場にドップリでたまにノマド開発者に化ける。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away