シェルスクリプトを書く時に、1行目に#!/bin/sh
(or #!/bin/bash
)を書きますよね。
「おまじない」と思って書いている方も多くいるのではないでしょうか。・・・私もその一人でした。
今回は、そんなおまじないに関するオプションのまとめです。
まずはじめに、sh
とbash
の違いについて説明します。(そんなのどうでもいいや!って人は読み飛ばしちゃってください)
sh
とbash
の関係
-
sh
- 標準のシェル
-
bash
- Linuxの標準シェル
-
sh
互換のコマンド言語インタプリタ
いずれのコマンドも標準入力やファイルから読み込んだコマンドを実行します。
ここで、bashとshの関係を見てみましょう。
ls
コマンドに-h
オプションをつけると、ディレクトリとファイルのパーミッション、所有者、グループ、サイズ、更新日などの詳細を表示することができます。
$ ls -l /bin/sh
lrwxrwxrwx. 1 root root 4 6月 8 14:30 /bin/sh -> bash
実行結果から、sh
とbash
には、シンボリックリンクが貼られていることがわかります。
sh
とbash
の違い
シンボリックリンクが貼られているので、 「sh
とbash
は全く同じでは?」と思うのですが、設定を見ると微妙に違っています。
適当な名前でシェルスクリプトを作成して、各コマンドで実行した結果を見てみましょう。
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記事を読んでみてください。
便利オプションたち
長々とsh
とbash
の違いを書いてしまいましたが、大事なのはここからです。
-
-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以外のステータスで終了しているため、以降のコマンドが実行されません。
$ /tmp/test.sh
command: test 1 -eq 2
-
-x
オプション
1行目を#!/bin/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
オプション
1行目を#!/bin/sh -v
に変更します。
-x オプションとは異なり、変数名がそのまま表示されることがわかります。
#!/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以外のステータスで終了するまでに、実際に実行されたコマンドと変数の値が展開された状態で表示されています。
$ ./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
ぜひ、便利オプションたちを使ってみてください。