シバン (Unix)

シェルスクリプトの先頭でインタープリタを指定するために使用される記号 From Wikipedia, the free encyclopedia

シバンまたはシェバン (: shebang) とはスクリプト#!から始まる1行目のこと。起動してスクリプトを読み込むインタプリタを指定する。

シェバンやシバンと呼ばれるようになった理由については諸説あるが、一般的には、そこに書かれる2文字が「#」(ハッシュ番号記号)と「!」(bang! バンびっくりマーク)だから、ハッシュ・バン(hash bang)やシャープ・バン(sharp bang)と呼ばれるようになり、それを短く言う際に訛ってシェバンとなった、と説明されている。あるいは、もはもともとは主にシェルを起動していたからシェル・バン(shell bang)と呼ばれ、それが訛ったと説明されることもある。いずれにせよ現在では、これらを縮めたシェバンという呼び方が一般的かつ簡素である[2]。日本の技術書ではシバンと3文字表記することも多い。

概要

シバンは基本的には、スクリプトを記述したファイルにおいて、スクリプトを実行するインタプリタのバイナリを指定するためのものである。

シバンが無かった時代には、スクリプトを実行させる場合、コマンドを書くたびにいちいち「インタプリタ名 + スクリプトのファイル名」を併せて書かなければならなかった。両方明記しなければスクリプトが動かないようでは、頻繁に実行する場合に特に煩わしい。シバンでインタプリタを指定できる仕組みを導入したことで、実行時にはファイル名だけを書けば済むようになった。

シバンを認識するのは、プログラムローダーである。つまり、オペレーティングシステム (OS) の execve システムコール(exec を参照)を処理するルーチン中のプログラムローダーである[注釈 1]

プログラムローダーはファイルの1行目の最初に「#!」を見つけると、1行目の残りの文字列をインタプリタを指定しているものとして扱い、そのインタプリタにこのファイルのパスを渡す。するとそのインタプリタはこのファイルのデータを入力データ(実行すべきスクリプト)として扱い、それを実行する。

インタプリタはシバンを無視する。なぜならシバンの最初の文字は「#」であり、インタプリタにとって「#」は、その行がコメント文だということを意味するからである。

1行目にシバンを書き、2行目以降にスクリプトの本文を書く。Bourne Shellのスクリプトだと以下のようになる。

#!/bin/sh
echo 'Hello world!'

典型的な例をいくつか示す。

  • #!/bin/sh - Bourne Shellでスクリプトを実行する。
  • #!/bin/bash - Bashでスクリプトを実行する。
  • #!/usr/bin/pwshPowerShellでスクリプトを実行する。
  • #!/usr/bin/env python3Python 3で、envプログラムを使いパスを探す。

注意点

  • シバン行の最大文字数、指定可能な引数の数などは環境依存である。それを逸脱した場合の動作も環境依存である。特に複数個の引数を与えた場合にどう扱われるかはまちまち(普通に扱われる、2個目以降は無視される、空白の入った1個の引数にされる)であるため、注意が必要である[2]
  • ファイルの先頭がバイト順マークになっているUnicode形式のファイルの場合は動作しない。これはバイト順マークのために、OSのプログラムローダーがシバンを認識できなくなるためである。

envコマンドを使う手法

envを使えるインタプリタがいくつかある。

Ruby言語のインタプリタ rubyenv コマンドを用いて実行する場合だと、以下のように書くことができる。

#!/usr/bin/env ruby
puts 'Hello world!'

ただし、envを用いる手法はPATH環境変数に依存する。親プロセスが独自にPATHを設定していた場合、想定外の動作をする可能性がある。ruby インタプリタの場合は -x オプションを利用した以下のようなシェルスクリプトに見せかけるトリックを使用したほうが良い。

#!/bin/sh
# -*- ruby -*-
exec ruby -x "$0" "$@"
#!ruby
puts 'Hello world!'

Java

Java 11以降はシバンがサポートされ、Java 25以降はコンパクトソースファイルがサポートされたため、以下のコードで動作する。ただし、ファイル名は拡張子 .java を付けてはならない。[3][4][5]

#!/usr/bin/java --source 25
void main() {
    IO.println("Hello, World!");
}

  • ラリー・ウォールのmetaconfigには、シバンを持たないシステムを検出し、スクリプトの先頭の<code>#!/bin/sh</code>: use /bin/shに置換する機能があった[注釈 2]
  • ELFでは類似の機能として、プログラムヘッダのINTERP型エントリにインタプリタを記述することが出来る。ここには実行可能バイナリが使用する動的リンクライブラリのパス名を設定する。OSは実行可能バイナリと同時にインタプリタとして指定された動的リンクライブラリもロードして動的リンクの処理をさせる。
  • FreeBSDのカーネルバイナリはインタプリタがカーネルでは使用されないことを逆手に取り、インタプリタとして/red/herringを指定している。[6]

歴史

シバンは、ベル研究所デニス・リッチーにより、Version 7 Unix(Unix 第7版)とVersion 8(Research Unix)の間の時期に導入された。また、カリフォルニア大学バークレー校のコンピューター科学研究グループによるBSDのリリースにも追加されており、2.8BSD には存在し、4.2BSD ではデフォルトで有効になっていた。ベル研究所の Version 8 Unix 以降の版は一般公開されなかったため、シバンが人々に広く知られるようになった最初の例はBSDとなった。

Version 7

シバンの一歩手前の段階。

インタプリタ指示子無しで、シェルスクリプトをサポートする、というやり方は1979年の Version 7 Unix のドキュメントに見られる。その説明によると、Bourneシェルの機能が実行権限を与えられたファイルを特別なものとして扱い、スクリプトの冒頭に「:」や「#」など特定の文字がある場合に、シェルがサブシェルを起動し、そのファイル内のコマンドを解釈・実行するという仕組みであった。 この方式では、スクリプトはBourneシェル内から呼び出されたときにのみ、通常のコマンドのように動作した。オペレーティングシステムの exec() システムコールを通じて直接スクリプトファイルを実行しようとしても失敗する仕様になっていたため、スクリプトは通常のシステムコマンドのように一貫して動作することはできなかった。

Version 8

「Unix第8版」(Version 8 Unix。Research Unix)以降では、スクリプトと実行ファイルの扱いが異なる問題は解消された。デニス・リッチーは、1980年1月のメールで、Unix第8版向けにインタプリタ指示子のサポートをカーネルに導入したことについて説明した。

From uucp Thu Jan 10 01:37:58 1980
>From dmr Thu Jan 10 04:25:49 1980 remote from research

The system has been changed so that if a file being executed
begins with the magic characters #! , the rest of the line is understood
to be the name of an interpreter for the executed file.
Previously (and in fact still) the shell did much of this job;
it automatically executed itself on a text file with executable mode
when the text file's name was typed as a command.
Putting the facility into the system gives the following
benefits.

1) It makes shell scripts more like real executable files,
because they can be the subject of 'exec.'

2) If you do a 'ps' while such a command is running, its real
name appears instead of 'sh'.
Likewise, accounting is done on the basis of the real name.

3) Shell scripts can be set-user-ID.

4) It is simpler to have alternate shells available;
e.g. if you like the Berkeley csh there is no question about
which shell is to interpret a file.

5) It will allow other interpreters to fit in more smoothly.

To take advantage of this wonderful opportunity,
put

#! /bin/sh

at the left margin of the first line of your shell scripts.
Blanks after ! are OK. Use a complete pathname (no search is done).
At the moment the whole line is restricted to 16 characters but
this limit will be raised.

以下、上記の翻訳。

From uucp Thu Jan 10 01:37:58 1980
>From dmr Thu Jan 10 04:25:49 1980 remote from research

システムが変更され、実行中のファイルがマジック文字「#!」で始まっている場合、行の残りの部分は実行ファイルのインタプリタ名として解釈されるようになりました。
以前は(そして実際今でも)、シェルがこの作業の多くを実行していました。
テキストファイルの名前がコマンドとして入力されると、シェルは自動的に実行モードでテキストファイル上で自身を実行していました。
この機能をシステム[注釈 3]に組み込むことで、次のような利点が得られます。

1) シェルスクリプトが、より一層、本物の実行可能ファイルのようになる。なぜなら、それらを `exec` の対象にできるからです。

2) そのようなコマンドを実行中に `ps` を使うと、`sh` の代わりに実際の名前が表示されます。同様に、アカウンティング(実行記録)も実際の名前で行われます。

3) シェルスクリプトに set-user-ID ビットを設定できるようになります。

4) 別のシェルを使うことがより簡単になります。たとえば、Berkeleyの csh を使いたい場合でも、どのシェルでスクリプトを解釈するかについて疑問が生じません。

5) 他のインタプリタもよりスムーズに組み込むことができます。

この素晴らしい機会を活かすには、シェルスクリプトの先頭行の左端に「#!/bin/sh」と記述してください。`!` の後に空白があっても問題ありません。完全なパス名を使用してください(検索は行われません)。現時点では、この行の全体は16文字に制限されていますが、この制限は今後引き上げられる予定です。

脚注

Related Articles

Wikiwand AI