【Mac/Linux】#!(シバン)とは?

このページにはプロモーションが含まれています

このページでは、シェルスクリプトや Python スクリプトの最初の行によく記載されている #! の意味について解説していきます!

# から始まるので単なるコメントであると考えている方も多いかもしれませんし、おまじないだと教えられた方もおられるかもしれません。実は、#! は単なるコメントではなく、非常に重要な意味合いのある記述となります。

#! とは

最初に結論を述べておくと、#! は Mac や Linux に用意されたスクリプトを実行するインタプリタを指定する仕組みとなります。#! はシバンと呼ばれます(シェバン・ハッシュバンとも呼ばれるようです)。

この #! はスクリプトの先頭行に記述します。そして、#! の後ろ側にはインタプリタのファイルパスを指定します。

#!の書き方
#!インタプリタのファイルパス

スクリプトの処理

例えば下記のように記述した場合、このスクリプトを直接実行すると、このスクリプトは /usr/bin/python から実行されることになります。

#!の記述例
#!/usr/bin/python

print('Hello World!()

#! の効果

正直、先ほどの解説が全てですし、先ほどの解説によって #! の意味合いについては理解していただけたのではないかと思います。

ですが、せっかくなので、ここから #! (シバン) の有無によるスクリプトの実行結果の違いを確認していきたいと思います。

Python スクリプトを例に説明していきますので、Python をインストールしている場合は自身で動作を確認しながら読み進めていただければと思いますが、読むだけでも #! については理解できると思います。また、Python は /usr/bin/python に存在することを前提として解説を進めていきます。

スポンサーリンク

#! の有無によるスクリプトの実行結果の違い

この #! (シバン) の効果を理解するためには、実際に #! の有無によってスクリプトの実行結果がどのように変化するのかを確認してみるのが早いと思います。

#! 無しの場合の Python スクリプトの実行結果

ここではまず、下記の Python スクリプトについて考えていきたいと思います。これは、お馴染みの print 関数で標準出力に Hello World! 出力されるだけのスクリプトになります。このスクリプトのファイル名は noshebang.py としたいと思います。

noshebang.py
print('Hello World!')

下記のようにコマンドを実行すれば、Hello World! と出力されることが確認できると思います。

% /usr/bin/python noshebang.py
Hello World!

それに対し、下記のコマンドを実行した場合はどうなるでしょうか?2行目で noshebang.pyを直接実行しており、1行目では noshebang.py を実行するために実行権限を付与するためのコマンドを実行しています。この実行権限については、後述の 実行権限に注意 で解説したいと思います。

% chmod 775 noshebang.py
% ./noshebang.py

お察しの通り、普通にエラーが発生します。私の環境では下記のようなエラーが発生しました。

./noshebang.py: line 1: syntax error near unexpected token `'Hello World!''
./noshebang.py: line 1: `print('Hello World!')'

#! が無しの場合の Python スクリプトの実行結果

では、次は下記のように #! (シバン) を追加したスクリプトで同様のことを行いたいと思います。このスクリプトのファイル名は shebang.py としたいと思います。

shebang.py
#!/usr/bin/python
print('Hello World!')

この場合、下記コマンドを実行した場合の動作はどうなるでしょうか?おそらく、今回の場合は、shebang.py の処理が正常に行われ、Hello World! と出力されることが確認できると思います。

% chmod 775 shebang.py
% ./shebang.py     
Hello World!

#! の有無によって実行結果が異なる理由

このように、noshebang.pyshebang.py とを直接実行した場合の結果は異なります。そして、この2つのスクリプトの違いは #!/usr/bin/python の有無のみとなりますので、この違いは #!/usr/bin/python の有無によって発生していることになります。

#! が存在する場合の動作

#! とは で説明した通り、#! は、そのスクリプトを実行するインタプリタを指定するための記述となります。したがって、#!/usr/bin/python が記述されているスクリプトの場合、例えば先ほどの例における shebang.py の場合、実行した際に /usr/bin/python から shebang.py が実行されることになります。

つまり、下記のコマンドを実行すれば、

% ./shebang.py

実際には下記が実行されることになります。

% /usr/bin/python ./shebang.py

このように、#! を記述することで、そのスクリプトを実行するインタプリタを指定することが出来ます。ここでは #!/usr/bin/python と記述しましたが、#!/usr/bin/env python という風に記述することもでき、実はこちらの方が書き方としては無難です。

#!/usr/bin/python を記述した場合、/usr/bin/python が存在しなければ実行時にエラーが発生することになります。それに対し、#!/usr/bin/env python を記述していた場合、PATH に設定されたフォルダから python が探索され、見つかった python が実行されることになります。

なので、#!/usr/bin/env python を記述しておけば、python ファイルの存在するフォルダに関わらず、そのスクリプトファイルを直接実行することができるようになります。

envの利用例
#!/usr/bin/env python
print('Hello World!')

ちなみに、PATH の意味合いや PATH の通し方については下記ページで解説していますので、PATH について詳しく知りたい方は是非下記ページも読んでみてください。

MacでのPATHの通し方の解説ページアイキャッチ MacOSX での PATH の通し方について解説

#! が存在しない場合の動作

#! が存在する場合の動作は、#! が実行するインタプリタを指定する記述であることを理解しておけば想像しやすいと思います。

では、#! が存在しない場合はどのように動作することになるのでしょうか?

おそらく、この時の動作は環境依存になると思います。私の環境の場合は、そのスクリプトが sh コマンドで実行されるようでした。

つまり、#! 無しの場合の Python スクリプトの実行結果 で紹介した noshebang.py を下記のように実行した場合、

% ./noshebang.py

実際に実行されるコマンドは下記のようなものになります。

% sh ./noshebang.py

要は、noshebang.py はシェルスクリプトとして実行されることになります。そして、noshebang.py は Python スクリプトであり、シェルからは解釈不能であるためエラーが発生したということになります。

なので、今回は Python スクリプトを例に解説してきたため、#! を記述せずに直接実行した際に確実にエラーが発生することになりましたが、シェルスクリプトの場合は #! を記述していなくても直接実行できたことになります。

であれば、シェルスクリプトの場合は #! の記述は不要であるかというと、ここは意見が分かれるところかもしれませんが、私は書いておいた方が無難だと思います。シェルには shbashzsh など、様々な種類のものが存在します。同じスクリプトであっても、実行するシェルによっては結果が異なる可能性があります。そして、前述の通り、#! を記述しなかった場合、実行されるインタプリタは環境依存となります。そのため、#! を記述しなかった場合、そのスクリプトが直接実行された際に意図しない結果となる可能性があります。例えばエラーが発生するなど。

ですが、#! を記述しておけば、実行時に利用されるインタプリタを明確に指定することができるため、スクリプト記述者の意図した結果が得られやすくなります。ということで、#! は記述しておいた方が良いというのが私の意見となります。

インタプリタをコマンドで指定した場合の動作

#! の有無によるスクリプト直接実行時の動作の違いについては理解していただけたのではないかと思います。ただし、スクリプトを実行するインタプリタはコマンドで指定することも可能です。例えば、下記のコマンドの場合、スクリプトを実行するインタプリタに sh をコマンド形式で指定することになります。

% sh shebang.py

さらに、スクリプトに #! が記述されている場合、スクリプトを実行するインタプリタをスクリプト内で #! によって指定することにもなります。この場合、コマンドで指定したインタプリタと #! で指定したインタプリタのどちらが採用されることになるのでしょうか?

この場合は、コマンドで指定したインタプリタによってスクリプトが実行されることになるようです。そのため、例えば #! にデタラメなファイルパスが記述されていても、コマンドでインタプリタを指定すれば正常に動作することになります。

実行権限に注意

最後に #! を利用して「直接スクリプトを実行する場合の注意点」について解説しておきます。

その注意点とは「実行権限」です。

Mac や Linux では、各ファイルに対する権限が管理されています。実行したいファイルは、そのファイルの実行権限を実行するユーザーに持たせておく必要があります。

ここまで解説してきたように、#! を記述しておくことで Python スクリプトなども直接実行することが可能となりますが、それはそのスクリプトの実行権限を持っている場合のみとなります。スクリプト自体の実行権限がない場合、#! の有無に関わらず、直接実行しようとしてもエラーが発生することになるので注意してください。

% ./test.py
zsh: permission denied: ./test.py

この実行権限の有無によるエラーの発生は、「スクリプトを直接実行する場合」と「他のインタプリタのコマンドから実行する場合」とで異なるという点が厄介です。例えば、Python スクリプトであれば下記のように python コマンドで実行することが多いと思います。

% python ./test.py

この場合、ユーザーに実行権限が必要となるのは python となります。上記コマンドによって実行されるのは python であり、test.pypython から読み込まれるファイルとなります。

実行権限が必要になるファイルの説明図

したがって、この場合は test.py に関しては読み込み権限さえあれば問題なく実行することができることになります。逆に言えば、test.py の実行権限を持っていたとしても、test.py の読み込み権限を持っていなければ実行時にエラーとなります。

それに対し、直接スクリプトを実行する場合、実行対象となるファイルはそのスクリプトとなります。実行すると、その後に #! で指定されたインタプリタから読み込まれて実行されることになるのですが、少なくとも最初に実行されるのはスクリプトファイルとなります。

実行権限が必要になるファイルの説明図2

したがって、そのスクリプトの実行権限を持っていなければエラーとなることになります。

まぁ、冷静に考えれば当たり前のことではあるのですが、いつも python から実行しているファイルを #! を利用して直接実行しようとした際にハマりがちな罠となりますので、この実行権限については注意が必要となると思います。

例えば、vim コマンド等でスクリプトを作成した場合、おそらくそのスクリプトにはデフォルトでは実行権限が設定されていないはずです。そのため、インタプリタのコマンドから実行した場合は上手く実行されるのに、直接実行しようとするとエラーが発生することになってしまいます。直接実行するためには、そのスクリプトファイルの権限を別途設定する必要があります。

そして、こういった権限の設定は chmod コマンドから行うことができます。例えば #! 無しの場合の Python スクリプトの実行結果 で示したように下記コマンドを実行してやれば、引数で指定したスクリプトファイルに実行権限が付与されることになります。そして、実行した際には、スクリプトファイルの #! で指定されるインタプリタから実行されることになります。

% chmod 775 test.py

この chmod コマンドに関しては下記ページでも解説していますので、詳細に関しては下記ページを参照していただければと思います。他にも便利なコマンド・Mac でコマンドを利用する場合に必須となるコマンドを紹介していますので、是非読んでみてください!少なくとも Mac や Linux をコマンドで利用する場合、chmod は必須のコマンドであるといって良いと思います。

Macのターミナルで良く使うコマンド集紹介ページのアイキャッチ Macのターミナルでよく使うコマンド集(初心者向け)

スポンサーリンク

まとめ

このページでは、スクリプトの先頭行に記述されることの多い #! (シバン) について解説しました!

#! ではスクリプトを直接実行した際に利用されるインタプリタの指定が行われます。そして、これにより例えば Python スクリプトなども直接実行することができるようになります。

結構目にする機会は多いものの、意味合いを理解していなかった方も多いのではないでしょうか?# から始まるので単なるコメントにも思えるかもしれませんが、#! は実は非常に重要な記述となります。

是非この機会に #! の意味合いについて覚えておいていただければと思います!

同じカテゴリのページ一覧を表示

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です