Pythonスクリプトの最初の行に#!/ usr / bin / env python shebangと書くのはなぜですか?


1047

その行がなくてもファイルは同じように実行されるように思えます。


1
以下の答えは、それが単なるコメント行であると述べています。いつもそうとは限りません。「Hello、World!」があります。#!/usr/bin/env python上部にのみWebページを実行および表示するCGIスクリプト(.py)。
Chakotay 2013年


動作する可能性がありますが、意図した環境では動作しません
ニコラスハミルトン

18
envハッシュバンを忘れることがあるので、この投稿を7年間で何度も訪れました。パスタをコピー:)
BugHunterUK 2017

回答:


1083

Pythonの複数のバージョンがインストールされている場合/usr/bin/envは、使用するインタプリタが環境の最初のインタプリタであることを確認します$PATH。代替案は、次のようなものをハードコーディングすることです#!/usr/bin/python。それは問題ありませんが、柔軟性が低くなります。

Unixでは、解釈されることを意図した実行可能ファイル#!は、最初の行の先頭にa を置き、その後にインタプリタ(および必要なフラグ)を付けることで、使用するインタプリタを示すことができます。

あなたが他のプラットフォームの話をしている場合は、当然のことながら、このルールは適用されません(ただし、その「シェバング行が」問題はありませんし、あなたがプラットフォームにそのスクリプトをコピーする場合に役立ちます、このようなLinuxの、マックなどのUnixベース、 、など)。


267
ただ、追加する:これは、あなたが(実行可能それを作ることにより、UNIXでそれを実行したときに適用されchmod +x myscript.py)、その後、それを直接実行している:./myscript.py、というだけよりもpython myscript.py
クレイグマックイーン

28
usingを使用envすると、ユーザーがPATHを変更して使用するインタープリターを選択できるという点で、最大の柔軟性が得られます。多くの場合、この柔軟性は必要ありませんが、たとえばLinuxではプロセス名にスクリプト名を使用できず、ps「python」に戻るという欠点があります。たとえば、ディストリビューション用のpythonアプリをパッケージ化するときは、使用しないようにアドバイスしますenv
pixelbeat

9
pyランチャーはWindowsでシバン行を使用できます。Python 3.3に含まれているか、個別にインストールできます
jfs 2013年

6
警告の重要な言葉、envの戻り値は最終的に期限切れになります。短期間のプロセスを実行している場合、これは影響を与える可能性はほとんどありません。しかし、/usr/bin/env: Key has expired何時間も経過した後、メッセージでプロセスが停止してしまいました。
malaverdiere 2017

4
@malaverdiereこの期限切れの動作を説明するリソースにリンクできますか?見つかりません。
マイケル

266

それはシバンラインと呼ばれています。Wikipediaのエントリ説明

コンピューティングでは、シバン(ハッシュバング、ハッシュプリング、ポンドバン、クランチバンとも呼ばれます)は、文字「#!」を指します。それらがテキストファイルの最初の行としてインタープリターディレクティブの最初の2文字である場合。Unixライクなオペレーティングシステムでは、プログラムローダーはこれらの2文字の存在をファイルがスクリプトであることを示し、ファイルの最初の行の残りの部分で指定されたインタープリターを使用してそのスクリプトを実行しようとします。

Unix FAQエントリも参照してください。

実行するインタープリターがシバン行で決定されないWindowsでも、シバン行でオプションを指定することにより、インタープリターにオプションを渡すことができます。一般的なシバン行を1回限りのスクリプト(SOで質問に答えるときに書いたスクリプトなど)で維持する便利です。そのため、WindowsとArchLinuxの両方ですばやくテストできます。

ENVユーティリティは、あなたがパス上でコマンドを呼び出すことができます:

残りの最初の引数は、呼び出すプログラム名を指定します。PATH環境変数に従って検索されます。残りの引数は、引数としてそのプログラムに渡されます。


30
Googleで簡単に検索できます-キーワードを知っている場合(「シバン行」は必須です)。
アラファンギオン

14
実際、この説明は、Googleで確認した他の参考資料よりも明確です。すべての潜在的な用途に対処するマニュアル全体を読むよりも、質問を対象とした1段落の説明を取得する方が常に優れています。
Sam Goldberg

1
@Arafangionおそらくこの質問が役に立つでしょう。TL; DR:symbolhound.com
ulidtko

@ulidtko:興味深い検索エンジンです。ジョンガルシアスの質問がより適切な回答になるように、回答を書くことを検討してください。
Arafangion、2015年

1
「shebang行で実行するインタープリターが決定されないWindowsでも、shebang行でオプションを指定することにより、インタープリターにオプションを渡すことができます。」それは単に誤りです。そのようなことが起こった場合、それはインタプリタ自体がシバン行を処理しているためです。通訳者がシバン行を特別に認識していない場合、そのようなことは起こりません。Windowsがシェバング線で何もしない「あなたはこのケースで記述することができることはpythonのランチャーです。python.org/dev/peps/pep-0397
カズ

154

他の答えを少し広げて、コマンドラインスクリプトが/usr/bin/envシバン行を慎重に使用することによってトラブルに陥る方法の小さな例を次に示します。

$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py 
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py 
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py 
Traceback (most recent call last):
  File "./my_script.py", line 2, in <module>
    import json
ImportError: No module named json

jsonモジュールはPython 2.5には存在しません。

この種の問題を防ぐ1つの方法は、ほとんどのPythonで通常インストールされるバージョン付きのpythonコマンド名を使用することです。

$ cat my_script.py 
#!/usr/bin/env python2.6
import json
print "hello, json"

Python 2.xとPython 3.xを区別するだけの場合は、Python 3の最近のリリースでもpython3名前が提供されています。

$ cat my_script.py 
#!/usr/bin/env python3
import json
print("hello, json")

27
うーん、それは私がその投稿から得たものではありません。
グレン・ジャックマン、2010年

1
ローカルとグローバルの違い。がをwhich python返す場合は/usr/bin/python、ローカルディレクトリパスをハードコードできます:#!/usr/bin/python。しかし、それは#!/usr/bin/env pythonグローバルなアプリケーションよりも柔軟性に欠けます。
noobninja

85

pythonスクリプトを実行するには、シェルに3つのことを伝える必要があります。

  1. ファイルがスクリプトであること
  2. スクリプトを実行するインタープリター
  3. 通訳の道

シバンは#!達成します(1.)。キャラクターは多くのスクリプト言語のコメントマーカーである#ため、シバンはaで始まり#ます。したがって、シバン行の内容はインタープリターによって自動的に無視されます。

envコマンドが実現(2)と(3)。「うれしさ」を引用すると

envコマンドの一般的な用途は、envが起動するように指示されたコマンドの$ PATHを検索するという事実を利用して、インタープリターを起動することです。シバン行では絶対パスを指定する必要があり、さまざまなインタープリター(perl、bash、python)の場所が大きく異なる可能性があるため、次のように使用するのが一般的です。

#!/usr/bin/env perl  / bin / perl、/ usr / bin / perl、/ usr / local / bin / perl、/ usr / local / pkg / perl、/ fileserver / usr / bin / perl、/ homeのいずれであるかを推測する代わりに/ MrDaniel / usr / bin / perl(ユーザーのシステム上)...

一方、envはほとんど常に/ usr / bin / envにあります。(そうでない場合を除いて、一部のシステムは/ bin / envを使用する場合がありますが、それはかなりまれなケースであり、Linux以外のシステムでのみ発生します。)


1
「うれしさ」どこ?
Pacerier 2017

44

おそらくあなたの質問はこの意味です:

使用したい場合: $python myscript.py

その行はまったく必要ありません。システムはpythonを呼び出し、次にpythonインタープリターがスクリプトを実行します。

ただし、使用する場合: $./myscript.py

通常のプログラムやbashスクリプトのように直接呼び出す場合は、その行を記述して、実行に使用するプログラムをシステムに指定する必要があります(また、で実行可能にするchmod 755


または、python3 myscript.py
vijay shanker

44

execLinuxカーネルのシステムコールはシバン(#!)をネイティブに理解します

bashを行う場合:

./something

Linuxでは、これはexecシステムコールをパスで呼び出します./something

カーネルのこの行は、httpsexec//github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25に渡されるファイルで呼び出されます

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

ファイルの最初のバイトを読み取り、それらをと比較します#!

比較が真の場合、行の残りの部分はLinuxカーネルによって解析され、最初の引数としてexecパス/usr/bin/env pythonと現在のファイルを使用して別の呼び出しを行います。

/usr/bin/env python /path/to/script.py

これは#、コメント文字として使用するすべてのスクリプト言語で機能します。

そして、はい、あなたは無限ループを作ることができます:

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bashはエラーを認識します。

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! たまたま人間が読めるだけですが、それは必須ではありません。

ファイルが異なるバイトで始まった場合、execシステムコールは異なるハンドラーを使用します。その他の最も重要な組み込みハンドラーは、ELF実行可能ファイル用です。https//github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305は、バイトをチェックします7f 45 4c 46(これは、人間にも起こります)読み取り可能.ELF)。/bin/lsELF実行可能ファイルであるの最初の4バイトを読み取ることで確認します。

head -c 4 "$(which ls)" | hd 

出力:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

そのため、カーネルがこれらのバイトを認識すると、ELFファイルを取得し、それをメモリに正しく配置して、新しいプロセスを開始します。参照:カーネルはどのようにLinuxで実行可能な実行可能バイナリファイルを取得しますか?

最後に、binfmt_miscメカニズムを使用して独自のシバンハンドラーを追加できます。たとえば.jarファイルのカスタムハンドラーを追加できます。このメカニズムは、ファイル拡張子によってハンドラーもサポートします。別のアプリケーションは、QEMUで異なるアーキテクチャの実行可能ファイル透過的に実行することです。

私はPOSIXがシバンを指定しているとは思いません:https ://unix.stackexchange.com/a/346214/32558 、それは根拠のセクションで、そして「実行可能スクリプトがシステムによってサポートされている場合、何かが起こる」。ただし、macOSとFreeBSDでも実装されているようです。

PATH 検索動機

おそらく、シバンが存在する大きな動機の1つは、Linuxでは、次のようにコマンドを実行したいということですPATH

basename-of-command

の代わりに:

/full/path/to/basename-of-command

しかし、シバンメカニズムがなければ、Linuxは各タイプのファイルを起動する方法をどのように知るのでしょうか。

コマンドでの拡張子のハードコーディング:

 basename-of-command.py

または、すべてのインタープリターにPATH検索を実装します。

python basename-of-command

可能性はありますが、コマンドを別の言語にリファクタリングすることを決定した場合、すべてが壊れるという大きな問題があります。

シバンはこの問題を美しく解決します。


39

技術的には、Pythonでは、これは単なるコメント行です。

この行は、シェルから(コマンドラインから)pyスクリプトを実行する場合にのみ使用されます。これはシバンとして知られています。、Pythonスクリプトだけでなく、さまざまな状況で使用されます。

ここでは、特定のバージョンのPython を起動するようにシェルに指示します(ファイルの残りの部分を処理します)。


シバンはUnixの概念です。Pythonランチャー をインストールしている場合は、Windowsでも動作することを言及する価値があるかもしれませんpy.exe。これは、標準のPythonインストールの一部です。
フロリスラ

38

これを行う主な理由は、オペレーティングシステム環境間でスクリプトを移植できるようにするためです。

たとえば、mingwの下では、pythonスクリプトは以下を使用します。

#!/c/python3k/python 

GNU / Linuxディストリビューションでは、次のいずれかです。

#!/usr/local/bin/python 

または

#!/usr/bin/python

そして、最高の商用Unix sw / hwシステム(OS / X)の下では、次のようになります。

#!/Applications/MacPython 2.5/python

またはFreeBSDの場合:

#!/usr/local/bin/python

ただし、これらすべての違いにより、以下を使用することにより、スクリプトをすべてに移植できます。

#!/usr/bin/env python

2
MacOSXでは、それも/usr/bin/pythonです。Linuxでは、システムによってインストールされたPythonもほぼ確実です/usr/bin/python(私は他に何も見たことがないので、意味がありません)。がないシステムがあるかもしれないことに注意してください/usr/bin/env
アルバート

1
!あなたがOSXにしていると自作を使用すると、デフォルトのインストール手順に従った場合、それは#は/ usr / local /ビン/ pythonの下になるだろう
ウィル

@ Jean-PaulCalderone:以下のsaajの回答を参照してください。
pydsigner 2015年

2018年の更新:Bare pythonはそれほどポータブルではなく、ディストリビューションのデフォルトのPythonインタープリターです。Arch Linuxは長い間デフォルトでPython 3を使用しますが、Python 2は2020
考慮している可能性があります。– mati865

22

最も見落としがちなことをすぐに理解できない可能性があることを強調することはおそらく意味があります。python端末に入力するとき、通常はフルパスを提供しません。代わりに、実行可能ファイルはPATH環境変数で検索されます。次に、Pythonプログラムを直接実行する場合は/path/to/app.py、使用するインタプリタをシェルに指示する必要があります(ハッシュバングを介して、他のコントリビュータが上で説明しているもの)。

Hashbangはインタープリターへのフルパス期待しています。したがって、Pythonプログラムを直接実行するには、特にvirtualenvの使用を考慮すると、大幅に異なるPythonバイナリへのフルパスを提供する必要があります。移植性に対処するためのトリック/usr/bin/envが使用されます。後者は元々環境をインプレースで変更し、そこでコマンドを実行することを目的としています。変更が提供されていない場合、現在の環境でコマンドを実行します。これにより、効果的に同じPATHルックアップが行われます。

unix stackexchangeからのソース


14

これは、どのプログラムがスクリプトを実行できるかをシェルに伝えるシェル規則です。

#!/ usr / bin / env python

Pythonバイナリへのパスに解決されます。



9

あなたはvirtualenvを使用してこの問題を試すことができます

ここにtest.pyがあります

#! /usr/bin/env python
import sys
print(sys.version)

仮想環境を作成する

virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7

各環境をアクティブにして、違いを確認します

echo $PATH
./test.py

9

使用するインタープリターを指定するだけです。これを理解するには、ターミナルからを実行してファイルを作成し、touch test.pyそのファイルに次のように入力します。

#!/usr/bin/env python3
print "test"

そして、行うchmod +x test.pyスクリプトを実行可能にします。この後、あなたが./test.pyするとき、あなたは言っているエラーを得るべきです:

  File "./test.py", line 2
    print "test"
               ^
SyntaxError: Missing parentheses in call to 'print'

python3は印刷演算子をサポートしていないためです。

次に、コードの最初の行を次のように変更します。

#!/usr/bin/env python2

testpython2が印刷演算子をサポートしているので、標準出力に印刷して機能します。これで、スクリプトインタープリターを切り替える方法を学びました。


9

その行がなくてもファイルは同じように実行されるように思えます。

もしそうなら、おそらくあなたはWindowsでPythonプログラムを実行していますか?Windowsはその行を使用しません。代わりに、ファイル名拡張子を使用して、ファイル拡張子に関連付けられているプログラムを実行します。

ただし、2011年には、このLinuxの動作をWindowsで(ある程度)模倣する「Pythonランチャー」が開発されました。これは、実行するPythonインタープリターを選択することだけに限定されます。たとえば、両方がインストールされているシステムでPython 2とPython 3のどちらかを選択します。ランチャーはpy.exe、Pythonのインストールと同様にオプションでインストールされ.py、ランチャーがその行をチェックして、指定されたPythonインタープリターバージョンを起動するようにファイルに関連付けることができます。


6
彼も使用して$ python myscript.pyいる可能性があります。
SinanÜnür2010年

私は行がないことでミスを犯し、python script.pyを使用しました。ある日./myscript.pyを実行しただけですべてが機能しなくなり、システムがファイルをpythonスクリプトではなくシェルスクリプトとして探していることに気付きました。
グアグア2014

8

これは、「実際の」答えよりも多くの履歴情報を意味します。

あなたはデザイナーのすべてのものを置く場所の独自の概念を持っていた、と時々のPython、Perlの、Bash、または他のGNU /オープンソースのものがたくさん含まれていませんでしたオペレーティングシステムのようなUNIXのLOTSた日にその背中を忘れないでくださいすべてのを

これは、さまざまなLinuxディストリビューションにも当てはまります。Linuxの場合-FHS以前[1]-/ usr / bin /または/ usr / local / bin /にpythonがある場合があります。または、インストールされていない可能性があるため、独自にビルドして〜/ binに配置しました

Solarisは、部分的にはBerkeley UnixからSystem Vへの移行として、私がこれまで取り組んだ中で最悪でした。/usr/、/usr/local/、/usr/ucb、/opt/などにあるもので終わる可能性があります。これにより、いくつかのために、本当に長いパス。Sunfreeware.comの各パッケージを独自のディレクトリにインストールしたことの思い出がありますが、バイナリが/ usr / binにシンボリックリンクされているかどうかは思い出せません。

ああ、そして時には/ usr / binがNFSサーバー上にあった[2]。

したがって、envユーティリティはこれを回避するために開発されました。

それからあなたは書くことができ#!/bin/env interpreter、パスが適切である限り、物事が実行される合理的なチャンスがありました。もちろん、妥当な意味(PythonおよびPerlの場合)は、適切な環境変数も設定したことを意味します。bash / ksh / zshの場合は機能しました。

これは、人々がシェルスクリプト(perlやpythonなど)を迂回していて、Red Hat Linuxワークステーションで/ usr / bin / pythonをハードコーディングした場合、SGIで問題が発生するため、重要でした。 、私はIRIXがpythonを正しい場所に置いたと思います。しかし、Sparcステーションではまったく動作しない可能性があります。

私のsparcステーションが恋しいです。しかし、多くはありません。さて、あなたは私にE-Bayをぶらぶらさせてもらいました。バステージ。

[1]ファイルシステム階層標準。https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

[2]はい、そして時々人々はまだそのようなことをします。いいえ、帯にはカブもタマネギも着用していません。


5

たとえば、仮想環境でスクリプトをvenv実行which pythonしているvenv場合、作業中に実行すると、Pythonインタープリターへのパスが表示されます。

~/Envs/venv/bin/python

仮想環境の名前は、Pythonインタープリターへのパスに埋め込まれていることに注意してください。したがって、スクリプトでこのパスをハードコーディングすると、2つの問題が発生します。

  • スクリプトをリポジトリにアップロードすると、他のユーザーに同じ仮想環境名を強制することになります。これは、最初に問題を特定した場合です。
  • あなたは、複数の仮想環境全体のスクリプトを実行することはできませんあなたが他の仮想環境内のすべての必要なパッケージを持っていた場合でも同様です。

したがって、ジョナサンの答えに加えて、理想的なシバンは#!/usr/bin/env python、OS間の移植性だけでなく、仮想環境全体の移植性でもあります。


3

との間の移植性の問題を考慮するpython2python3、プログラムが両方と互換性がない限り、常にどちらかのバージョンを指定する必要があります。

いくつかのディストリビューションは、出荷されているpythonにシンボリックリンクpython3今しばらくの間-に依存しないpythonことpython2

これはPEP 394で強調されています:

プラットフォーム間の違いを許容するには、Pythonインタープリターを呼び出す必要があるすべての新しいコードでpythonを指定するのではなく、python2またはpython3(またはより具体的なpython2.xおよびpython3.xバージョンを指定する必要があります。移行に関する注意事項を参照) 。この区別は、シェルスクリプトから呼び出す場合、system()呼び出しを介して呼び出す場合、または他のコンテキストで呼び出す場合に、シバンで行う必要があります。


2

複数バージョンのpythonがある場合に、プログラムを実行するpythonのバージョンをインタープリターに指示します。


0

使用する実行可能ファイルを選択できます。これは、おそらく複数のpythonインストールがあり、それぞれに異なるモジュールがあり、選択したい場合に非常に便利です。例えば

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $ALTERNATIVE_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

-8

これは、pythonディレクトリがどこにあるかをスクリプトに伝えます!

#! /usr/bin/env python
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.