シェルスクリプトの1行目に書くおまじないで使える便利オプション集

シェルスクリプトを書く時に、１行目に`#!/bin/sh`（or `#!/bin/bash`)を書きますよね。
「**おまじない**」と思って書いている方も多くいるのではないでしょうか。・・・私もその一人でした。
今回は、そんなおまじないに関するオプションのまとめです。

まずはじめに、`sh`と`bash`の違いについて説明します。（そんなのどうでもいいや！って人は読み飛ばしちゃってください）
# `sh`と`bash`の関係
* `sh`
  * 標準のシェル
* `bash`
  * Linuxの標準シェル
  * `sh`互換のコマンド言語インタプリタ

いずれのコマンドも標準入力やファイルから読み込んだコマンドを実行します。

ここで、bashとshの関係を見てみましょう。
`ls`コマンドに`-h`オプションをつけると、ディレクトリとファイルのパーミッション、所有者、グループ、サイズ、更新日などの詳細を表示することができます。

```sh:/bin/shとbashの関係
$ ls -l /bin/sh
lrwxrwxrwx. 1 root root 4  6月  8 14:30 /bin/sh -> bash
```

実行結果から、`sh`と`bash`には、**シンボリックリンクが貼られている**ことがわかります。

## `sh`と`bash`の違い
シンボリックリンクが貼られているので、 「`sh`と`bash`は全く同じでは？」と思うのですが、設定を見ると微妙に違っています。

適当な名前でシェルスクリプトを作成して、各コマンドで実行した結果を見てみましょう。

```sh:シェルスクリプトの中身
set -o
```
`set`コマンド（シェルのオプションを設定）に`-o`オプションをつけると、**現在設定されているシェルオプションの一覧を表示**することができます。

```sh:実行結果
$ bash test.sh | grep posix
===================
posix          	off
===================

$ sh test.sh | grep posix
===================
posix          	on
===================
```

* [POSIX](http://www.unix.com/man-page-posix-repository.php)の設定がon/offになっているかが違います。
  * POSIXがonの場合、要求された機能を完備している
  * POSIXがoffの場合、必要とされる機能が使えなかったり、実行内容が異なったりします


詳しく知りたい方は、こちらのqiita記事を読んでみてください。

* [POSIX シェルの組み込みコマンド一覧](http://qiita.com/magicant/items/b7f7f7526193e5c8dc00)

# 便利オプションたち
長々と`sh`と`bash`の違いを書いてしまいましたが、大事なのはここからです。

* `-e`オプション
  * 実行したコマンドが**0でないステータスで終了**した場合、即座に終了するオプション。
* `-x` オプション
  * シェルスクリプト内で実際に実行されたコマンドを表示するオプション。
  * 変数が使用されている場合は、その変数の値が展開された状態で表示される。

* `-v`オプション
  * シェルスクリプト内でこれから実行されるコマンドを表示するオプション。
  * 変数が使用されている場合は -x オプションとは異なり、変数名がそのまま表示される。

では、実際に各オプションを使ったシェルスクリプトを実行してみましょう。

## 各オプションつけて実行した結果

適当にシェルスクリプトを作成します。
このスクリプトでは、0でないステータスで終了するために、`test 1 -eq 2`（1は2と等しいか？）というコマンドをあえて実行します。
`$?`は、直前に実行したコマンドの終了ステータスが格納されます。

```sh:シェルスクリプトの中身
$ cd /tmp
$ vim test.sh
===================
#!/bin/sh

ONE=1
TWO=2

echo "command: test ${ONE} -eq ${TWO}"
test ${ONE} -eq ${TWO}
echo status: $?

echo "command: test ${ONE} -eq ${ONE}"
test ${ONE} -eq ${ONE}
echo status: $?
===================

# 実行権限をつける
$ chmod +x test.sh
```

* 何もオプションをつけていない場合

全てのコマンドが問題なく実行されます。
また、`test 1 -eq 2`の終了ステータスが`1`となっていることがわかります。

```sh:実行結果
$ ./test.sh
command: test 1 -eq 2
status: 1              ← 終了ステータス
command: test 1 -eq 1
status: 0              ← 終了ステータス
```
* `-e`オプションをつけて実行した場合

１行目を`#!/bin/sh -e`に変更します。
この状態で実行すると、0以外のステータスで終了しているため、**以降のコマンドが実行されません。**

```sh:-eオプション付き実行結果
$ /tmp/test.sh
command: test 1 -eq 2
```
* `-x`オプション

１行目を`#!/bin/sh -x`に変更します。
この状態で実行すると、実際に**実行されたコマンド**と**変数の値が展開された状態で表示**されていることがわかります。

```sh:-xオプション付き実行結果
+ ONE=1
+ TWO=2
+ echo 'command: test 1 -eq 2'
command: test 1 -eq 2
+ test 1 -eq 2
+ echo status: 1
status: 1
+ echo 'command: test 1 -eq 1'
command: test 1 -eq 1
+ test 1 -eq 1
+ echo status: 0
status: 0
```
* `-v`オプション

１行目を`#!/bin/sh -v`に変更します。
-x オプションとは異なり、**変数名がそのまま表示**されることがわかります。

```sh:-vオプション付き実行結果
#!/bin/sh -v

ONE=1
TWO=2

echo "command: test ${ONE} -eq ${TWO}"
command: test 1 -eq 2
test ${ONE} -eq ${TWO}
echo status: $?
status: 1

echo "command: test ${ONE} -eq ${ONE}"
command: test 1 -eq 1
test ${ONE} -eq ${ONE}
echo status: $?
status: 0
```

### オプションの合わせ技
* １行目を`#!/bin/sh -ex`に変更します（全部組み合わせることもできます）

0以外のステータスで終了するまでに、実際に**実行されたコマンド**と**変数の値が展開された状態で表示**されています。

```sh:-eと-xオプションの合わせ技
$ ./test.sh
+ ONE=1
+ TWO=2
+ echo 'command: test 1 -eq 2'
command: test 1 -eq 2
+ test 1 -eq 2
```

# まとめ
シェルスクリプトの1行目に書く、おまじないで使える便利オプションをまとめました。
正常以外で終了した場合、それ以降のコマンドを実行したくない時に`-e`オプションを使うと良いと思います。
`-x`や`-v`オプションはシェルスクリプトのデバッグに利用できます。

このオプションは1行目にも書くことができますが、`set`コマンドを使って以下のように利用することもできます。

```sh:オプションの別の指定方法
#!/bin/sh

set -e
```

ぜひ、便利オプションたちを使ってみてください。