シェルにはいくつかの起動方法がある。以下表のとおり、各起動方法の違いは、カレントプロセスで起動するか、別のプロセスで起動するか、スクリプトファイルに実行権限があるかないかによる。
起動方法 | プロセス | 補足 |
---|---|---|
. {シェルスクリプト名} | カレント | sourceと同様 |
source {シェルスクリプト名} | カレント | .(ドット)と同様 |
bash {シェルスクリプト名} | 別プロセス | シェルスクリプトに実行権限(x)がない場合でも利用可能。 |
{シェルスクリプト名} | 別プロセス | シェルスクリプトに実行権限(x)がある場合に利用可能 |
これらの実行方法の違いがどのような影響をもたらすか、簡単なスクリプトを用意して動きを確認する。まず下記のスクリプトを作成。名前は「sub.sh」。自分のシェル名とSAY変数を出力するだけのスクリプトである。SAY変数はどこにも定義されていない。
sub.sh#!/bin/bash
echo "$0 -> ${SAY}"
次にsub.shを呼び出すシェルを作成する。名前は「main.sh」。上記表の4つの方法でsub.shを実行する。またSAY変数を定義する。
main.sh#!/bin/bash
echo "start"
SAY="Hello!"
. ./sub.sh
source ./sub.sh
bash ./sub.sh
./sub.sh
echo "finish"
main.shの実行結果は以下となる。
main.shの実行結果$ ./main.sh
start
./main.sh -> Hello!
./main.sh -> Hello!
./sub.sh ->
./sub.sh ->
finish
解説:最初の2つ(ドットとsourceで実行したシェル)は、main.shと同じプロセスで実行されるので、SAY変数が参照できる。よって、Hello!と出力される。 またシェル名がsub.shではなく、main.shと出力されている。一方、最後の2つは別プロセスで起動されるため、SAY変数が参照できない。よって、何も表示されない。またシェル名は自分のファイル名(sub.sh)が表示されている。
シェルの実行方法の違いで、気を付けなければいけないのがexitである。例えば、ドットやsourceでカレントプロセスを使って起動した場合、sub.shでexitを実行すると、呼び出し元(main.sh)もろとも終了してしまう。 別プロセスでシェルを実行した場合は、あくまでそのプロセスだけ終了し、呼び出し元のシェルには影響しない。
カレントプロセスで起動する場合は、呼び出し元と一心同体になると思っておくとよいだろう。長くなったスクリプトを別ファイルに切り出したい時などに使える。 無駄にプロセス数も増やさないですむ。プロセス内で変数が共有できるというメリットもある。反面、exitが使えないため、条件によって処理を終了させたい場合などに不便なこともある(特に関数を作成した場合)。 当然、呼び出し元で$?も使えないため、処理が正常に終了したか失敗したかの確認も面倒になる。