シェルスクリプトを書く時、よく #!/bin/bash
とか #!/bin/sh
とか書くけど、これが何かっていうとそのファイルを実行するためのインタプリタのパスを指定している。シバンとかシェバンとか言うらしいけど、日常生活で用いたことは余裕で一度もない。 !
をBangって言うから、シェル・バンとか、#
と !
でハッシュバンとか言うらしい。
例えば下記のコマンドは自分のプロセスを表示する。ログインシェルはzshを使っている。
$ ps -p $$
PID TTY TIME CMD
48577 ttys004 0:00.46 -zsh
これを下記のようにシェルスクリプトにして、chmod +x a.sh
とかで実行権限を与える。シバンはbashのパスを指定している。
# !/bin/bash
ps -p $$
これを実行すると
$ ./a.sh
PID TTY TIME CMD
49563 ttys004 0:00.00 /bin/bash ./a.sh
bashで実行されている。
このシバンを下記のように変更する。
# !/bin/sh
ps -p $$
で、実行する。
$ ./a.sh
PID TTY TIME CMD
49698 ttys004 0:00.00 /bin/sh ./a.sh
shで実行されている。じゃあ、シバンを #!/bin/zsh
にするとどうなるかっていうと、
$ ./a.sh
PID TTY TIME CMD
49812 ttys004 0:00.01 /bin/zsh ./a.sh
大方の予想通りzshで実行される。ちなみに実行時パスが通っていても、シバンは絶対パスじゃないと動かないらしい。
# !zsh
ps -p $$
$ ./a.sh
zsh: can't open input file: \nps -p $$\n\M-|:D^E^A
要するにシバンとはスクリプトを実行するために、どのパスのインタプリタを使用するかということを絶対パス指定している。込み入ったシェルスクリプトを書くことはあんまりないけど、ときどき、 #!/usr/bin/env ruby
とか指定されていることがある。これは env
コマンドはパスの通ってるコマンドを実行するので、各環境のパスが通ったインタプリタにスクリプトを渡す、ということを表している。
シバンにはオプションも使える。(ものがある)例えばbashのシェルスクリプトは、ケースによって、よく -eux
を渡すようにしている。 e
はシェルスクリプト内で実行されたコマンドの返り値が0以外だったらシェルスクリプトを停止させる、 u
は未定義の変数参照を許さない、 x
はデバッグ情報を出力する。
変数未定義
$ cat a.sh
# !/bin/bash -eux
echo $HOGE
$ ./a.sh
./a.sh: line 3: HOGE: unbound variable
エラー時シェルスクリプト停止
$ cat a.sh
# !/bin/bash -eux
command_arimasen
echo "todoke"
$ ./a.sh
+ nainai_command
./a.sh: line 3: command_arimasen: command not found
ちなみにどうやって実行されているかというと
cat a.sh
# !/bin/bash -eux
ps -p $$
上記を実行すると単純にオプションが渡されているのが分かる。
$ ./a.sh
+ ps -p 50934
PID TTY TIME CMD
50934 ttys004 0:00.00 /bin/bash -eux ./a.sh