UNIX/Linuxの部屋 用語集:シェバング


※空白区切りで AND 検索 (例:「ファイル 削除」)

用語集 シェバング シェルなどのインタプリタを起動するための「#!」。shebang。

sh・csh・perl・ruby などのスクリプトの先頭行は
#!/bin/sh
#!/bin/csh -f
#!/usr/bin/perl
などと記述するが、この「#!」のことを「シェバング」(shebang) と呼ぶ。また、この行全体を「シェバング行」と呼ぶこともある。シェバングの語源は「sharp bang」「shell bang」など、いくつかあるようだ。

コンピュータが直接解釈できるのはマシン語だけである。しかし UNIX では、ファイルの先頭 2バイトが「#!」であった場合は、その後に記述されている別のコマンドを実行しようとする。

例えばシェルスクリプト hoge.sh の先頭行が
#!/bin/sh
であるとしよう。
% ./hoge.sh
と実行しようとしたとき、カーネルは hoge.sh の先頭 2バイトが「#!」であるため、その後に続く「/bin/sh」を実行するが、その際スクリプトのファイル名が引数として渡される。

つまり、
% ./hoge.sh

% /bin/sh ./hoge.sh
は (基本的には) 等価である。

% ./hoge.sh arg1 arg2 arg3
とコマンドラインで引数を指定した場合は
% /bin/sh ./hoge.sh arg1 arg2 arg3
と等価となる。

シェバング行に引数があった場合、たとえば fuga.csh の先頭行が
#!/bin/csh -f
の場合は以下のようになる。
% ./fuga.csh
⇒ /bin/csh -f ./fuga.csh と等価
% ./fuga.csh arg1 arg2 arg3
⇒ /bin/csh -f ./fuga.csh arg1 arg2 arg3 と等価

sh・csh・perl・ruby などは、# から始まる行をコメント扱いすることに注意しよう。1行目のシェバング行はただのコメントとしてスルーされるわけである。
% cat fuga.csh
#!/bin/csh -f
(略)
% ./fuga.csh
⇒ /bin/csh -f fuga.csh と等価
% /bin/csh ./fuga.csh
⇒ /bin/csh ./fuga.csh と等価 (シェバング行はただのコメント扱い)

シェバング行にはシェルや perl などの言語だけではなく、どんなコマンドでも書ける (それが役に立つかは別の話)。例えば、
#!/bin/cat -n
hoge
fuga
というファイル selfcat を作り、それを実行すると
% ./selfcat
1 #!/bin/cat -n
2 hoge
3 fuga
と自分自身を行番号付きで表示する。この場合は
% /bin/cat -n ./selfcat
相当のコマンドが実行されたわけである。

Tips.1
sh や csh のバイナリはまず間違いなく /bin 直下に置かれているため、
#!/bin/sh
#!/bin/csh
などと書けばよい。しかし perl や ruby などの新しめのコマンドは、OS によって /usr/bin にあったり /usr/local/bin にあったりと、置き場所がバラバラである。そこで
#!/usr/bin/env ruby
などと env コマンドを使用することが多い (特に ruby 界隈でよくみかける)。どこの ruby コマンドが実行されるかは、実行時に設定されている環境変数 PATH の内容次第であるため、確実性には少し欠ける。

ただし /usr/bin/env がない環境も少ないながら存在するため万能ではない。例えば 10.2 (Jaguar) より前の Mac OS X では /usr/bin/env がない。あと、AIX だか IRIX だか Tru64 も /usr/bin/env ではなく /bin/env だったはず。

Tips.2
シェバング行に
% cat hoge.sh
#!/bin/cmd -a -b -c def #comment
(略)
などと複数のオプションを指定した場合の挙動は OS によって異なる。上記スクリプトを
./hoge.sh
と実行した場合、各 OS では以下のように解釈される。

Linux・IRIX・Tru64・AIX・HP-UX・Mac OS X:
/bin/cmd "-a -b -c def #comment" ./hoge.sh
⇒ 全ての引数がひとつにまとめられる
FreeBSD 2.2.7-RELEASE:
/bin/cmd "-a" "-b" "-c" "def" ./hoge.sh
⇒ 引数がひとつずつ渡されるが # 以降は捨てられる
FreeBSD 4.0-RELEASE:
/bin/cmd "-a" "-b" "-c" "def" "#comment" ./hoge.sh
⇒ # 以降も含め、引数がひとつずつ渡される。
FreeBSD 5.5-RELEASE:
/bin/cmd "-a -b -c def #comment" ./hoge.sh
⇒ Linux などの多数派と同じ挙動になるよう修正
Solaris8:
/bin/cmd -a ./hoge.sh
⇒ 最初の引数しか渡されない。
参考: http://lists.freebsd.org/pipermail/freebsd-arch/2005-February/003525.html

移植性を重視するなら、シェバング行の引数はひとつだけにしておこう。もし複数の引数を記述する必要があるなら、以下のようなシェルスクリプトにすることをお勧めする。
#!/bin/sh
exec /bin/cmd -a -b -c def "$0" "$@"

Tips.3
シェバング行に記述するコマンドは、必ずバイナリでなくてはならい。
a.sh
#!/home/user/b.sh
b.sh
#!/bin/sh
(略)
という 2ファイルがあるとする。このとき、
% ./a.sh
は動かない (エラーにもならない。終了ステータスは 0)。シェバング行に書かれているコマンドがスクリプトであった場合は、再帰的なシェバングの解析は行われない (FreeBSD 5.2.1-RELEASE・Linux・Solaris8・HP-UX11i で確認)。ただし、a.sh を
#!/usr/bin/env /home/user/b.sh
と env コマンドを使うようにするという逃げ道はある。

Tips.4
perl のシェバング解析は、UNIX 界においてはかなり「変」である。perl は自前でシェバング行を解析してオプションを読み取ろうとする。sh や csh はこういうことはしない。
% cat foo.pl
#!/usr/bin/perl -w
(略)
% ./foo.pl
⇒ /usr/bin/perl -w foo.pl と等価
% /usr/bin/perl foo.pl
⇒ perl がシェバング行を解析して -w オプションを読み取るため、結局は /usr/bin/perl -w foo.pl と等価となる
perl は sh スクリプトさえも実行してくれる (perl がシェバング行を読んで、/bin/sh を実行しているだけ)。
% cat bar.sh
#!/bin/sh
echo This is sh-script

% perl bar.sh
This is sh-script

Tips.5
UNIX の改行コードは LF (0x0A) であるが、スクリプトの改行コードを CR LF (0x0D 0x0A) にしてしまうと、シェバング行の解釈時に「Command not found」となるが、エラーメッセージがわかりづらいのではまらないように。

Tips.6
スクリプトの名前を -h などとすると、大抵の場合うまく動作しなくなる。
% cat ./-h
#!/usr/bin/perl
(略)

% -h
Usage: perl [switches] [--] [programfile] [arguments]
(略)
⇒ /usr/bin/perl -h と実行されるが、ファイル名である -h がオプションと誤認されたため

よって、シェバング行には
#!/usr/bin/perl --
と、オプションの終わりを表す -- を付けた方がよい。ただし、当ページ管理人はそこまで気を遣ったりはしない。わざわざ -h なんてファイル名に変更する方が悪い。

Tips.7
シェバング行の最大長は OS によって異なるが、かなり小さいものもある。移植性を考えると、128バイト以内におさめた方がよい。ちなみに FreeBSD 4.4-RELEASE 以前の最大長は 64バイト、SunOS4 は 32バイトであった。

Tips.8
emacs (mule) では、ファイルの 1行目に特定の書き方をすることで、メジャーモードなど各種設定を行うことができる。

「-*-」と「-*-」の間に hoge と書くと、hoge-mode になる。
#!/usr/bin/perl # -*- perl -*-
⇒ このファイルを emacs で開くと自動的に perl-mode になる。
これはシェバングとは直接は関係ない。例えば C であっても
/* -*- lisp -*- */
main(){ ... }
と書けば lisp-mode になる。

普通は「拡張子 .c は c-mode」「.pl は perl-mode」などと拡張子でモード設定を行うので、このような書き方は必要ないが、どうしても拡張子がないスクリプトを書かざるをえなくなったときに活用するとよい。

Tips.9
今どきの UNIX では、シェバング行を解析するのはカーネルの役割である。ただし はるか昔の UNIX、例えば NEWS-OS はライブラリ exec*(3) 側でシェバング行を解析していた、とNeco氏がどこかで語っていたような気がする。

Tips.10
シェバングに関する、より詳細な情報は以下の URL を参照のこと。


頑張って書いたおすすめコンテンツ!
クラウドサービス徹底比較・徹底解説