ShellScript
Bash
sh
シェルスクリプト

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

More than 1 year has passed since last update.

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

まずはじめに、shbashの違いについて説明します。(そんなのどうでもいいや!って人は読み飛ばしちゃってください)

shbashの関係

  • sh
    • 標準のシェル
  • bash
    • Linuxの標準シェル
    • sh互換のコマンド言語インタプリタ

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

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

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

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

shbashの違い

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

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

シェルスクリプトの中身
set -o

setコマンド(シェルのオプションを設定)に-oオプションをつけると、現在設定されているシェルオプションの一覧を表示することができます。

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

$ sh test.sh | grep posix
===================
posix           on
===================
  • POSIXの設定がon/offになっているかが違います。
    • POSIXがonの場合、要求された機能を完備している
    • POSIXがoffの場合、必要とされる機能が使えなかったり、実行内容が異なったりします

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

便利オプションたち

長々とshbashの違いを書いてしまいましたが、大事なのはここからです。

  • -eオプション
    • 実行したコマンドが0でないステータスで終了した場合、即座に終了するオプション。
  • -x オプション

    • シェルスクリプト内で実際に実行されたコマンドを表示するオプション。
    • 変数が使用されている場合は、その変数の値が展開された状態で表示される。
  • -vオプション

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

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

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

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

シェルスクリプトの中身
$ 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となっていることがわかります。

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

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

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

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

-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オプション

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

-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

オプションの合わせ技

  • 1行目を#!/bin/sh -exに変更します(全部組み合わせることもできます)

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

-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コマンドを使って以下のように利用することもできます。

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

set -e

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