Python スクリプトでは、if __name__ == '__main__':
という記述をしばしば見かけます。この if 段落内のコードは、- スクリプトを直接起動した場合、実行される
- 他のスクリプトから import された場合は、実行されない
という動作をします。
これによって、スクリプトの単体試験容易性を確保できる (単体試験用スクリプトから試験対象のスクリプトを import して関数単位の試験実施ができる) というメリットがありそうです。ぜひ、シェルスクリプトにもこの記法が欲しいですね。
bash ではスクリプトファイルのコールスタックが BASH_SOURCE 配列に格納されるので、これの配列長を見ることでコンテキストの判定をしてみます。
すなわち、BASH_SOURCE の配列長が 1 であれば、実行中のコードの記述されたスクリプトが直接起動されたと判断できそうです。
というわけで、実験してみます。2 つのファイルを用意します。
ファイル 1: lib_foo.sh (インポートされる側)#!/bin/bash
function foo() {
echo "foo! foo!"
}
[ ${#BASH_SOURCE[@]} = 1 ] && {
echo "foo: begin"
foo
echo "foo: end"
}
ファイル 2: foo_caller.sh (インポートする側)#!/bin/bash
. ./lib_foo.sh
foo
それぞれ実行権限を与えて、コマンド実行してみると…$ ./lib_foo.sh
foo: begin
foo! foo!
foo: end
$ ./foo_caller.sh
foo! foo!
ということで、foo_caller.sh では lib_foo.sh をインポートしつつ、foo 関数だけを実行することができました。[ ${#BASH_SOURCE[@]} = 1 ] && { ... }の箇所は、お好みに応じてif [ ${#BASH_SOURCE[@]} = 1 ]; then
# ...
fiなどでもよいですね。
... と、ここまで書いておいてアレですが、シェルスクリプトの単体試験を行うことができるフレームワークとして shUnit2 なるものがあるそうです。フレームワーク自体もシェルスクリプトで書かれているという時点でハマりどころのありそうな香りがプンプンしますがちょっと楽しそうなので、今度触ってみようと思います。
追記(2012/06/18)
Web を検索してみると、[ "${BASH_SOURCE}" = "${0}" ]という条件で同じことを判別しようとしているサンプルがありますが、これはダメです (スクリプト内で自分自身を source したケースを考えてみると分かりますね)。