いまさら聞けない、#! で始まる1行目の名前とenv指定時の挙動


シェルスクリプトであれば1行目に #!/bin/sh と書くと思うのですが、1行目の名前や挙動についてよく分かってなかったので調べてみました。

名前

シバン (Unix) - Wikipedia

シバンまたはシェバン (shebang) とはUNIXスクリプトの#!から始まる1行目のこと。起動してスクリプトを読み込むインタプリタを指定する。 hash-bangまたはsharp-bangとも言うが、後者を縮めたshebangという呼び方が一般的かつシンプルである。

シバンというのですね。

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

この「#!」のことを「シェバング」(shebang) と呼ぶ。また、この行全体を「シェバング行」と呼ぶこともある。シェバングの語源は「sharp bang」「shell bang」など、いくつかあるようだ。

なぜ、#! なのか

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

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

env を使う場合の挙動について

シバン (Unix) - Wikipedia

/usr/bin/env を使えばパスを直接指定する必要はなくなるが、インタプリタコマンドライン引数としてオプションを渡すことができない。

インタプリタコマンドライン引数としてオプションを渡すことができない。」とはどういうことでしょうか。Rubyで実験してみます。

rubyコマンドラインオプションを渡せない実験

'-v'' オプションを使って実験します。

envを使わない場合
% echo '#!/usr/local/bin/ruby -v' > hoge
% chmod 755 hoge
% ./hoge
ruby 1.8.6 (2009-06-08 patchlevel 369) [i686-linux]
envを使う場合
% echo '#!/bin/env ruby -v' > hoge
% chmod 755 hoge
% ./hoge
/bin/env: ruby -v: そのようなファイルやディレクトリはありません

'ruby -v 'というもので1つの引数となっているようです。念のため、#!/bin/env ruby でちゃんとrubyが使えるか実験です。

% echo '#!/bin/env ruby' > hoge
% echo 'puts "Hello World!"' >> hoge
% chmod 755 hoge
% ./hoge
Hello World!

rubyコマンドラインオプションを渡せない理由

[ruby-list:41934] Re: Cygwin での #!/bin/env ruby -Ks

多くのOSでは#!記法は引数を一つしか受け付けないので、オプションを付けて呼び出したい時にはenvは使えません。envを使うとrubyインタプリタをPATHから検索してくれるので便利なこともあるんですけどね。

実験環境

OS CentOS release 5 (Final)
Ruby 1.8.6 (2009-06-08 patchlevel 369) [i686-linux]

おまけ:Mac OS X 10.6.2 でやったら env でも複数の引数が渡せた

envを使わない場合
% echo '#!/opt/local/bin/ruby -v' > hoge
% chmod 755 hoge
% ./hoge
ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10]
envを使う場合
% echo '#!/usr/bin/env ruby -v' > hoge
% chmod 755 hoge
% ./hoge
ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10]

env でも ruby -v が実効できました。Macはうまいことやってくれているのですかね。

おまけ:実験環境

OS Mac OS X 10.6.2

おまけ2:不正なシバンが無視される場合

不正なシバンが無視される場合があります。

#!/opt/local/bin/rubyfoooooooooooo                                                   
puts "test"

以下の結果を見ると、コマンドラインインタプリタを指定するとシバンを無視するようです。

% ruby shebang_test.rb 
test
%
% ./shebang_test.rb 
zsh: ./shebang_test.rb: bad interpreter: /opt/local/bin/rubyfoooooooooooo: no such file or directory

しかし、以下の例は無視されません。

#!/opt/local/bin/hogefugabazfoooooooooo
puts "test"

実行結果は「Can't exec」になります。シバンに ruby の文字が有るか無いかで判断しているようです。

% ruby shebang_test.rb 
shebang_test.rb:1: Can't exec /opt/local/bin/hogefugabazfoooooooooo (fatal)

この辺り、Twitterで少しやりとりがありました。

おまけ2:実験環境

OS Mac OS X 10.6.2

まとめ

誤解している部分もあるかと思いますので、ツッコミお願いします><