デバッグ

前回、以下の様なスクリプトを作成しました。

#!/bin/bash
V_OPTION=$1

if test ${V_OPTION} = "bash"
then
    echo "Hello bash World!!"
elif test ${V_OPTION} = "Linux"
then
    echo "Hello Linux OS!!"
fi

要件は以下の2点

・第一オプションが「bash」だったら「Hello bash World!!」と表示する。
・第一オプションが「Linux」だったら「Hello Linux OS!!」と表示する。

確かに要件を満たしているので、前回のスクリプトでも正解と言えない事もありません。
ですが、このスクリプトには問題点がいくつかあります。

まずは1つ目の問題から

・例外処理がされていない。

上記2つの要件を満たしているのですが、それ以外のパターンの事が一切考えられていません。
例えば、「bash」と「Linux」以外のオプションだった場合、どのような動作をするでしょうか?

# ./helloworld3.sh bsd
# 
# ./helloworld3.sh linux
# 
# ./helloworld3.sh 
./helloworld3.sh: line 4: test: =: unary operator expected
./helloworld3.sh: line 7: test: =: unary operator expected
# 

オプションに「bsd」や「linux」とつけてみました。何も表示されませんね。
オプションを何もつけなかった場合はどうでしょう。何やらエラーが出力されています。
この様に、想定している事以外の結果を「例外」と言い、この例外に関する処理を「例外処理」と言います。
今回のスクリプトの場合、「bsd」と「linux」が引数付与された場合の動作は想定通りとしても
最低限、引数が付与されなかった時、エラーが出力される事は避けるべきです。

2つ目の問題点
・if文の動作が何やらおかしい

オプションを何もつけずに動かした場合、以下の様なエラーが発生していました。

./helloworld3.sh: line 4: test: =: unary operator expected
./helloworld3.sh: line 7: test: =: unary operator expected

このエラーはなんでしょうか?
4行目と7行目がおかしい様ですが、パッと見ただけでは判りませんね。
こういう時は、詳細な処理ログを見れば判る時が多々あります。

bashスクリプトでは、詳細な処理ログを「-x」オプション付与によって出力してくれます。
スクリプト1行目の

#!/bin/bash

#!/bin/bash -x

に変更し、スクリプトを実行してみましょう。

まずは正常動作時のログから

# ./helloworld3.sh bash
+ V_OPTION=bash
+ test bash = bash
+ echo 'Hello bash World!!'
Hello bash World!!
# 

次は、オプションを何もつけなかった時のログ

# ./helloworld3.sh
+ V_OPTION=
+ test = bash
./helloworld3.sh: line 4: test: =: unary operator expected
+ test = Linux
./helloworld3.sh: line 7: test: =: unary operator expected
#

やはり判定文の所がおかしいですね。test文で比較対象となるべき文字列がなにもありません。
4行目と7行目はどの様な判定文を書いていたでしょうか?

#!/bin/bash -x
V_OPTION=$1

if test ${V_OPTION} = "bash"
then
    echo "Hello bash World!!"
elif test ${V_OPTION} = "Linux"
then
    echo "Hello Linux OS!!"
fi

大体想像つきましたか?
本来、第一オプションが格納されるはずの「V_OPTION」変数に何も格納されていないので、それを比較しようとして動作がおかしくなっているようです。
bashの変数は文字列と数字を格納する事ができますが、何も格納されていないこの状態の時、 変数内には「null」が格納されています。数字でも文字列でも無い、敢えて言うならば「何も無い」という状態です。
「何も無い」という状態と「bash」や「Linux」という文字列を比較した場合、比較対象が真か偽の判断がつかない為、エラーが出力されている事になります。

では、この2点の問題を修正しましょう。

1点目の問題点を修正する為には、「例外処理」を加えるだけで大丈夫です。

if文の例外処理はelse以後に記入します。

2点目の問題点の修正方法は「変数(実行時に付与されたオプション)が文字列である」という事を明確にする事で大丈夫です。

「echo」文でやっている通り、文字列を出力する場合、文の最初と最期に「"」を付けて括っています。
変数の場合も、文字列を扱う場合、「"」で変数を括る事により、文字列だと言うことを明示的にする事ができます。

それでは、以下の様にスクリプトを修正し、実行してみましょう。

#!/bin/bash 
V_OPTION=$1

if test "${V_OPTION}" = "bash"
then
    echo "Hello bash World!!"
elif test "${V_OPTION}" = "Linux"
then
    echo "Hello Linux OS!!"
else
    echo "Hello World!!"
fi

 

# ./helloworld3.sh bash
Hello bash World!!
# ./helloworld3.sh Linux
Hello Linux OS!!
# ./helloworld3.sh bsd
Hello World!!
# ./helloworld3.sh linux
Hello World!!
# ./helloworld3.sh 
Hello World!!
# 

上記の様に表示されましたか?
「bash」と「Linux」以外のオプション、もしくはオプションが付かなかった時の動作として、「Hello World!!」と出力するようにしてみました。
では、オプションに何も渡されなかった時の処理ログを見てみましょう。

スクリプト1行目を

#!/bin/bash -x

に変更し、オプションを付与しないでスクリプトを実行してみましょう。

# ./helloworld3.sh 
+ V_OPTION=
+ test '' = bash
+ test '' = Linux
+ echo 'Hello World!!'
Hello World!!

文字列の判定文では変数を「"」で括るようにしました。これによって変数に格納されているのは「null」ではなく空文字列と判断され、
処理ログを見ても判る通り、判定が可能となります。

これでひとまず、このスクリプトのデバッグ処理は終了です。