初めてシェルスクリプトを書くときに知っておきたいこと
他の言語をを書き慣れてから、シェルスクリプトを書こうとするとしょうもない部分でハマったりすることがあります。「簡単な処理だからシェルスクリプトで書くか」と思っても無駄に時間がかかってしまっては仕方ないですよね。
今回は初めてシェルスクリプトを書くときに、ハマりそうな点について説明をしたいと思います。
実行権限をつける
単純にファイルを生成しても下記の用に実行しようとしても実行はできません。
# touch test
# ./test
sh: ./test: Permission denied
# touch foo
# ./foo
sh: ./foo: Permission denied
これはファイルに実行権限がついていないため、起きる現象です。
chmodコマンドを使って実行権限をつけてやりましょう。
# chmod +x test
# ./test
# chmod +x foo
# ./foo
エラーメッセージは返らずに、無事実行できたと思います。
まずシェルスクリプト用のファイルを生成したら実行権限をつけるようにしましょう。
実行するプログラムを指定する
よくおまじないと言われる記述部分です。これは、ここにおいてあるプログラムを使用してそれ以降を実行させましょうという意味になります。
今回はBourneShellを想定していますので下記のように指定をしましょう。
#!/bin/sh
Perlを書いたことある人なら似たような記述をしたことがあると思います。
これは指定したPATHのPerlを使用しなさいって意味なので、shに関しても同様になります。
変数をセットする
自分はこれが最初はハマりました・・・かなり基本的な部分ですが他の言語とことなるので意識をしておく必要があります。
まず簡単なサンプルコードを以下に記載します。
ここでのポイントは2点あります。
- 変数をセットする時の=(イコール)の前後にはスペースをいれないこと
- セットするときには、$はつけないが、展開するときには$をつけること
まず1点目は、他の言語を書き慣れている方にはかなり特殊に感じる部分だと思います。ここに半角スペースを1個でも入れてしまうとエラーが発生して、シェルスクリプトは動作しません。
次に2点目ですが、代入するときと利用するときで$をつける、つけないが変わってくるのでこれもしっかりと覚えておきましょう。
条件判定をさせる( testコマンド を使用する )
シェルスクリプトでも他の言語と同様に、ifを使って条件分岐をさせることができます。
if文で条件を記載するtest部分(スクリプト上は [ ] で記述する)部分の記述方法が特殊なのでこちらも押さえておく必要があります。
サンプルは以下のコード。
#!/bin/sh
touch TESTFILE
if [ -e TESTFILE ]
then
echo "OK"
else
echo "NG"
fi
上記は2行目でtouchしたTESTFILEというファイルが存在するかどうかをチェックして条件分岐をさせている例になります。
次は数値の比較の例を示したいと思います。
#!/bin/sh
NUM=0if [ $NUM -eq 0 ]
then
echo "OK"
else
echo "NG"
fi
上記はNUMに代入した数値と0を比較しています。-eqという記述が数値比較となっているのが分かるかと思います。
こちらも独特な記述ですね。
testコマンドのオプションを簡単にまとめたいと思います。主に自分がよく使うものなので、一部です。
- ファイルのチェック
- -e ファイル名
- 指定したファイルがあれば真
- -s ファイル名
- 指定したファイルサイズが0より大きければ真
- 文字列チェック
- -n 文字列
- 文字列の長さが0より大きければ真
- 文字列 = 文字列
- 2つの文字列が等しければ真
- 文字列 != 文字列
- 2つの文字列が等しくなければ真
- 数値のチェック
- 数値1 -eq 数値2
- 2つの数値が等しければ真
- 数値1 -ge 数値2
- 1が数値2以上であれば真
- 数値1 -gt 数値2
- 数値1が数値2より大きいのであれば真
- 数値1 -le 数値2
- 数値1が数値2以下であれば真
- 数値1 -lt 数値2
- 数値1が数値2未満であれば真
- 数値1 -ne 数値2
- 2つの数値が等しくなければ真
また、先ほどの変数に代入する際の=の記述と同様にこちらも半角スペース縛りがあります。
[ 変数 -eq 数値 ]
と記述する際、[の直後と]の直前には半角スペースを入れてください。これを入れないと動作しません。
コマンドの実行結果を利用する
コマンドの実行結果を変数に代入したいときは、そのコマンドを`(バッククオート)で囲みその結果を変数に入れます。
サンプルコードは以下。
#!/bin/sh
HOSTNAME=`hostname`
echo $HOSTNAME
上記はhostnameというコマンドを一度変数に代入をしてから表示をさせている例になります。
Lockファイルを生成する
シェルスクリプトでおおいパターンがcronで定時に実行するというパターンだと思います。しかしながら、Backupの処理などある程度長時間かかることが想定される際は、2重起動をさせないようにしておく必要があります。
そういった際は、起動時にlockfileを生成し、終了時に削除をするようにし、そのファイルが存在するときは起動をさせないようにします。
サンプルコードは以下。
#!/bin/sh
LOCKFILE=/tmp/.lock
if [ -e $LOCKFILE ]
then
echo "Already Running"
else
touch $LOCKFILE
echo "OK"
sleep 10
rm $LOCKFILE
fi
上記の記述では、起動時にLockファイルをチェックしファイルが無かった場合のみに処理を実行させ最後にLockファイルを削除してLockを解除しています。
(かなり簡単すぎますか)この記述方法で2重起動を防ぐことができます。
コマンドの終了ステータスをチェックする
事前に実行したコマンドの結果によって処理を分けたいときがあると思います。そんな時は、$?をつかって事前のコマンドの終了ステータスをチェックしましょう。
サンプルコードは以下。
#!/bin/sh
host google.jp > /dev/null
echo $?host hoge > /dev/null
echo $?
上記のコードを実行すると、下記のように表示されると思います。
0
1
これはコマンドの実行結果によって返ってくる値が変わってくるためです。
testコマンドと組み合わせて使えばば事前のコマンドの終了ステータスをとることによって条件を分岐させて、などというようなこともできます。