コードの先頭に#!/usr/bin/env ruby
と書くやつ。
shebang(シバン)
shebang(シバン、シェバン)とは、ファイルを実行するインタプリタを指定したコードのこと。そのファイル自身の1行目の行頭に#!
で始まる。
効果
a.rb
p 'A'
ruby a.rb
このとき、シバンを書けばインタプリタruby
を省略できる。
a.rb
#!/usr/bin/env ruby p 'A'
実行権限を付与する。
chmod +x a.sh
以下のようにファイルを指定するだけで実行できるようになる。
./a.sh
シバンは効果的か?
シバンは効果的か?
シバン書かないほうがよかったのでは?
ruby a.rb
を./a.rb
にするためにやったことは以下。
- ファイル先頭にシバンを追加した:
#!/usr/bin/env ruby
- ファイル実行権限を付与した
- 相対パス
./
を追加した
あれ、シバンのほうが作業量もコード量も多くない?
元々ruby a.rb
は文字数としてもruby
とスペース1字しかなかった。そしてシバン実行するときは./
が必要である。2文字余分に増えた。つまり差し引き3文字分しか短縮できていない。それだけのためにシバンを追記したり実行権限を付与したわけだ。はたして割りに合っているといえるだろうか。
しかも後述するが、シバンの動作は環境依存である。
せめてシバンに複雑な引数が渡せたらよかった。それなら短縮できる効果は高い。だが、それもやはり環境依存だし、$0
などの変数も使えないようだ。
そもそもインタプリタを選別するくらいなら、ほとんどがファイル拡張子でできるのでは? シェルがファイル拡張子から自動で判断してくれたほうが嬉しかった。
語源
"shebang"は"Hash Bang"の略。
「#」をハッシュと呼ぶのは元々北米以外の英語圏での慣習
"Bang"は「!」の俗称だ。叩いたり銃を撃ったりしたときの音の擬声語
私としては以下だと思っていた。
shell bangからという説もある
ユースケース
直接パス指定
#!/bin/bash
bashスクリプトファイルの先頭を上記のようにする。直接インタプリタbash
のフルパスを指定している。
パスについてはwhich
で調べればよい。
> which bash /bin/bash
Rubyコマンドについて調べてみた。
> which ruby /home/{user}/.anyenv/envs/rbenv/shims/ruby
なので絶対パス指定するとシバンは以下のようになる。
#!/home/{user}/.anyenv/envs/rbenv/shims/ruby
このパス、完全に環境依存だよね。Linuxのディレクトリ構成だし、{user}
に至ってはOSのユーザ名だし。anyenv
を使って環境構築するとは限らないし。
envによるパス指定
#!/usr/bin/env bash
env
を介してパス指定する。インタプリタの絶対パスはOSによって異なる可能性がある。そこでenv
を介することで絶対パス表現を避けている。ただしenv
コマンドは絶対パス指定せねばならない。
Rubyのときは以下。
#!/usr/bin/env ruby
Wikipediaによると、Rubyのときは以下のほうが良いと書いてあった。
envを用いたトリックはPATH環境変数に依存する。親プロセスが独自にPATHを設定していた場合、想定外の動作をする可能性がある。ruby インタプリタの場合は -x オプションを利用した以下のようなシェルスクリプトに見せかけるトリックを使用したほうが良い。
#!/bin/sh # -*- ruby -*- exec ruby -x "$0" "$@" #!ruby puts 'Hello world!'
LinuxのディストリビューションFreeBSDでは、env
シバンだと動作しないらしい。
ただ、それでも多くのOSで動作する。それにRubyだけシェルスクリプトにみせかけるトリックを使用のも面倒だし、そのコード量が多すぎる。よって、普段はenv
トリックを用いることにする。
所感
ここまで苦労してシバンを選別して記述したとして、効果はどれほどあるだろうか。費用対効果まで考えると微妙かもしれない。完璧に動作保証されたシバンを書きたいものだ。環境依存はとてもモヤモヤして気持ちが悪い。
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- bash 5.0.3(1)-release
- Ruby 3.0.2
$ uname -a Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux