#!/bin/sh は ただのコメントじゃないよ！ Shebangだよ！

**(2017.01.23 追記) 本記事のコメントも併せてご覧ください！**

## 何の話？
- シェルスクリプトなどでみる`#!/bin/sh`は一体何なのかという話

### 読むとHappyになれる可能性のある人
- ファイル冒頭の`#!/usr/bin/env python`というような記述をコメントだと思っている人
- コメントじゃないことは知っているが何だか分からない人

### 前置き
```py:hello.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

print('Hello from Python 3.x')
```

```rb:hello.rb
#!/usr/bin/env ruby
puts 'Hello from Ruby'
```

`#!/usr/bin/env python`とか`#!/usr/bin/env ruby`という記述をたまに(？)見かけますよね。こやつらは一体何だ？ というのがこの記事の話題です。

特に私のようにWeb系のプログラミング言語から入った人はよくわからない人が多いのではないかと思います(私も先日まで知らなかったです)。
「なんかおまじないでしょ？」とか「別に書かなくても動くじゃん？」とか「えっ！ 単なるコメントじゃないのこれ！」みたいな人は読んでおくといいかもしれません。

### 結論
- `#!`で始まる行のことをShebangという
- Shebangにより使用するインタプリタの指定をする
- Shebangの発音はカタカナで書くなら「シバン」とか「シェバン」とか
- ~~Unix系に携わるエンジニアなら記述しましょう~~ 実行ファイルとして動かすには記述が必要
- (副次的な効果として)何のファイルか分かりやすい

## 書きながら理解しましょう
### 環境
- MacOS 10.11.x
- Ruby 2.3.0(rbenv利用)
- 環境によってはうまくいかないかもしれません

### Rubyファイルをコマンドとして実行する
```rb:sample01.rb
#!/usr/bin/env ruby
puts 'Hello from Ruby'
```

このファイルをターミナル上で素直に実行してみます。

```bash:
$ ruby sample01.rb
Hello from Ruby
```

何の変哲もない。単にRubyで記述されたスクリプトを実行しただけです。
次に、この`sample01.rb`を**コマンドとして**実行してみます。

```bash:
$ ./sample01.rb
-bash: ./sample01.rb: Permission denied
```

パーミッションに関していじっていなければこうなる(デフォルトは大体644だと思う)。
では、実行権限を設定してあげましょう。

```bash:
$ chmod +x sample01.rb
```

改めてコマンドとして実行します。

```bash:
$ ./sample01.rb
Hello from Ruby
```

というわけで**コマンドとして**実行できたわけです。

### `#!/usr/bin/env ruby`の記述は何なのか
これはインタプリタの指定をしています。

ここで「えっ！ インタプリタって何？」となった人はググりましょう。
一応インタプリタをイメージで説明すると、人間が書いたスクリプト(今回は`sample01.rb`)を機械のために翻訳してくれるやつのことですね。

今回はRubyのインタプリタを指定しているので、うまく解釈してくれたわけです。
では、インタプリタを別の言語のものにするとどうでしょうか？

```rb:sample02.rb
#!/usr/bin/env python
puts 'Hello from Python'
```

今度はPythonのインタプリタを指定しています。
先程と同様にパーミッションを追加してみると

```bash
$ chmod +x sample02.rb 
$ ./sample02.rb 
  File "./sample02.rb", line 2
    puts 'Hello from Ruby'
                         ^
SyntaxError: invalid syntax
```

エラーが返ってきました。これはどういうことでしょうか？

これはこのスクリプトをPythonのインタプリタで解釈したことによるエラーです。記述内容やファイル拡張子はRubyですがインタプリタの指定がPythonになっているためです(Pythonに `puts` という命令はない)。

それを確かめるためにRubyにはないPythonのメソッドを記述してみましょう。

```rb:sample03.rb
#!/usr/bin/env python
print(type('Hello'))
```

```bash
$ ./sample02.rb 
<class 'str'>
```

インタプリタをRubyに戻すとRubyとしてのエラーが返ってきます。

```rb:sample04.rb
#!/usr/bin/env ruby
print(type('Hello'))
```

```bash
$ ./sample02.rb 
./sample02.rb:2:in `<main>': undefined method `type' for main:Object (NoMethodError)
```

### Shebang それは `#!`で始まる1行目の記述
`#!`で始まる1行目の記述はShebangと呼びます(「シバン」や「シェバン」と発音するらしい)。

```rb:sample04.rb
#!/usr/bin/env ruby
puts 'Shebang'
```

という実行権限が与えられたスクリプトがあるとします。
この状況で、

```bash
$ ./sample04.rb
Shebang
```

となります。これは今まで見てきたとおりです。

何が起こっているかというと、カーネルが `sample04.rb` の先頭2バイトが`#!`なので、それに続く`/usr/bin/env ruby`を実行するのですが、このときに**スクリプトの内容が引数として渡されます**。

つまり、

```bash
$ /usr/bin/env ruby ./sample04.rb
```

と

```bash
$ ./sample04.rb
```

は同じ意味になります。

[参考: UNIXの部屋 コマンド検索: shebang](http://x68000.q-e-d.net/~68user/unix/pickup?keyword=shebang&target=command)

### うまくいかない場合もある
今回記述した `#!/usr/bin/env ruby` という記述は多くの環境では動くと思いますが、環境によっては `/usr/bin/env` が存在しない場合もあるので念のため注意です。

[参考: Perl, Python 及び Ruby スクリプトにおける正しいshebangの書き方](http://qiita.com/tueda/items/369215b99316b2e9f3d8)

### Shebangは書くべきなのか？
仕組みがある程度わかったところで実用面の話です。要するに**Shebangは書くべきなのか**ということですが、~~結論「書くべきだ」という方向のようですね。~~

~~特に、bashのシェルスクリプトの場合は明示した方が良さそうです。~~

**2017.01.23 訂正 コメントより引用**
「Shebang書くべきなのか？」

> じゃなくて、書かないと実行ファイルとして動かせませんから。
>> 問題は、
>> ・`/bin/sh` では、シェルが何なのかは判らない
>> ・パスが合っていないかもしれない。 `/bin` にあったり `/usr/bin` にあったり、`/usr/local/bin` にあったり、もしかすると辺境の地にあるかもしれない

> 前者は、実行させたいシェルを明示することで解決 eg. /bin/bash
> 後者は、env で解決（することが多い）


[参考: シェルスクリプトの罠を避ける三つの tips - Shebang に bash を明示しろ](http://qiita.com/magicant/items/f3554274ee500bddaca8#shebang-%E3%81%AB-bash-%E3%82%92%E6%98%8E%E7%A4%BA%E3%81%97%E3%82%8D)
[参考: シェルスクリプトの冒頭でbashを明示する（提案）](http://qiita.com/jkr_2255/items/84366f677be3365331cd)


## おまけ
### Shebangの由来
諸説あるようですが、Shebangは Hash(#) と Bang(!) をくっつけた HashBang の省略形らしいです。「!」はBangなんですね。知らなかった。

### rbenv使用下でのインタプリタのパス
rbenvを使っていればRubyのインタプリタのパスは `/Users/ユーザ名/.rbenv/versions/2.3.0/bin/ruby` 
になっていると思うのでShebangを次のように書いても動きます。

```rb:sample.xxx(拡張子は何でもいい)
#!/Users/ユーザ名/.rbenv/versions/2.3.0/bin/ruby
puts 'Hello'
```

```bash
$ chmod +x sample.xxx
$ ./sample.xxx
Hello
```

```rb:
# インタプリタのパスを得る
require 'rbconfig'
Ruby = File::join(RbConfig::CONFIG['bindir'],
                  RbConfig::CONFIG['ruby_install_name'])
Ruby << RbConfig::CONFIG['EXEEXT']

puts Ruby
```

[参考: [ruby]インタプリタのパスを得る](http://d.hatena.ne.jp/mugaki/20101013/1286945611)

以上