web-dev-qa-db-ja.com

#!/ bin / shはインタープリターによって読み取られますか?

bashまたはshでは、#で始まるものはすべてコメントであると思います。

ただし、bashスクリプトでは次のように記述します。

#!/bin/bash

Pythonスクリプトには、次のものがあります。

#!/bin/python

これは、#自体はコメントですが、#!はコメントではないということですか?

65
Gaurav Sharma

#!行が使用されますbeforeスクリプトが実行され、無視されますwhenスクリプトが実行されます。

シェバンライン と通常のコメントの違いは何ですか。

#!で始まる行は、#で始まる他の行と同じくらいのコメントです。これは、#!がファイルの最初の行、またはその他の場所にある場合に当てはまります。 #!/bin/sh効果があります、ただしインタプリタ自体によって読み取られません

#はすべてのプログラミング言語のコメントではありませんが、ご存知のように、shbashを含むBourneスタイルのシェル(およびcshなどのほとんどの非Bourneスタイルのシェル)のコメントです。 Pythonのコメントでもあります です。そして、それは実際にはまったくスクリプトではないさまざまな構成ファイル内のコメントです(/etc/fstabなど)。

シェルスクリプトが#!/bin/shで始まるとします。これはコメントであり、インタープリター(シェル)は#文字の後の行のすべてを無視します。

#!行の目的は、インタープリターに情報を提供することではありません。 #!行の目的は、オペレーティングシステム(またはインタープリターを起動するプロセス)にインタープリターとして使用するものを伝えることです。

  • たとえば、./script.shを実行して実行可能ファイルとしてスクリプトを呼び出す場合、システムは#!で始まり、その後に0個以上のスペースがあり、その後にコマンドが続くかどうかを最初の行で調べます。存在する場合、スクリプトの名前を引数としてそのコマンドを実行します。この例では、/bin/sh script.sh(または技術的には/bin/sh ./script.sh)を実行します。

  • 明示的にインタープリターを呼び出してスクリプトを呼び出す場合、#!行は参照されません。したがって、sh script.shを実行すると、最初の行は効果がありません。 script2.shの最初の行が#!/usr/games/nibblesの場合、sh script2.shを実行しても、nibblesでスクリプトを開こうとしません(ただし、./script2.shは開きます)。

どちらの場合も、スクリプトの拡張子(.sh)があれば、それが実行方法に影響することに気付くでしょう。 Unixライクなシステムでは、これは通常、スクリプトの実行方法に影響しません。 Windowsなどの一部のシステムでは、#! Shebang行がシステムによって完全に無視され、スクリプトを実行するものが拡張機能によって決定される場合があります。 (これは、スクリプトの拡張機能を提供する必要があるという意味ではありませんが、それが正しい場合、それが正しいはずである理由の1つです。)

#!は、この目的を正確に果たすために選択されました理由#はコメントを開始します。 #!行はインタープリターではなくシステム用であり、インタープリターによって無視される必要があります。

Bashスクリプトのシバンライン

あなたは(元々)bashスクリプトに#!/bin/shを使用すると言っていました。スクリプトがbashの拡張機能を必要としない場合にのみ、これを行う必要があります---shはスクリプトを実行できる必要があります。 shは、常にbashへのシンボリックリンクではありません。多くの場合、 すべてのリモートの最近のDebianおよびUbuntuシステム を含めて、shdashへのシンボリックリンクです。

Pythonスクリプトのシェバンライン

また、(質問の最初のバージョンで、編集する前に)Pythonスクリプトを#!/bin/sh read by the interpretorで開始すると述べました。あなたが文字通りそれを意味するなら、あなたはそれを絶対にやめるべきです。 hello.pyがその行で始まる場合、./hello.pyを実行すると次が実行されます。

/bin/sh read by the interpretor hello.py

/bin/shは(by the interpretor hello.pyを引数として)readというスクリプトを実行しようとしますが、readは(できれば)検出されず、Pythonスクリプトは決して表示されません。 Pythonインタープリター。

この間違いを犯しているが、私が説明している問題が発生していない場合、おそらくインタープリター(たとえば、python hello.py)を明示的に指定してPython scripsを呼び出し、最初の行を引き起こしています。無視されます。スクリプトを他の人に配布したり、しばらくしてから使用したりする場合、それらが機能するためにこれが必要であることは明らかではないかもしれません。今すぐ修正するのが最善です。または、少なくとも最初の行を完全に削除して、./で実行に失敗したときにエラーメッセージが意味をなすようにします。

Pythonスクリプトの場合、Pythonインタープリターの場所がわかっている(または、今後予定されている)場合は、#!行を同じ方法で記述できます。

#!/usr/bin/python

または、Python 3スクリプトの場合、 pythonはほとんど常にPython 2 であるため、python3を指定する必要があります。

#!/usr/bin/python3

ただし、問題は、/bin/shは常に存在するはずであり、/bin/bashはほとんど常に、bashがOSに付属しているシステムに存在するが、Pythonはさまざまな場所に存在する可能性がある。

したがって、多くのPythonプログラマーが代わりにこれを使用します。

#!/usr/bin/env python

(またはPythonの場合は#!/usr/bin/env python3 3.)

これにより、スクリプトは、envが正しい場所にあるのではなく、pythonが「正しい場所」にあることに依存します。それは良いことです、なぜなら:

  • envはほとんどの場合、/usr/binにあります。
  • ほとんどのシステムでは、pythonshouldを実行すると、PATHで最初に表示されるスクリプトが実行されます。 hello.py#!/usr/bin/env pythonで開始する./hello.pyを実行する/usr/bin/env python hello.pyは、python hello.pyを実行するのと(実質的に)同等です。

#!pythonを使用できない理由は次のとおりです。

  • 指定したインタープリターに絶対パス(つまり、/で始まる)を指定する必要があります。
  • 呼び出しプロセスはpython現在のディレクトリ内 を実行します。コマンドにスラッシュが含まれていないときにパスを検索することは、特定のシェルの動作です。

Pythonまたはシェルスクリプトではない他のスクリプトには、#!/bin/sh ...で始まるShebang行が含まれることがあります。ここで、...は他のコードです。これは、Bourne互換シェル(sh)を引数付きで呼び出してPythonインタープリターを呼び出す方法があるため、これは正しい場合があります。 (おそらく引数の1つはpythonを含むでしょう。)ただし、ほとんどの目的では、#!/usr/bin/env pythonはより単純で、よりエレガントで、望みどおりに動作する可能性が高くなります。

他の言語のシバン線

多くのプログラミングおよびスクリプト言語、およびその他のファイル形式では、#をコメントとして使用します。いずれの場合も、言語のファイルは、#!の後の最初の行でプログラムを指定することにより、それを引数として取るプログラムによって実行できます。

一部のプログラミング言語では、#は通常コメントではありませんが、特別な場合として、#!で始まる場合、最初の行は無視されます。これにより、#!が行をコメントにしない場合でも、#構文の使用が容易になります。

スクリプトとして実行されないファイルのシバン行

直感的ではありませんが、ファイル形式が#!で始まり、実行可能ファイルのフルパスが続く最初の行に対応できるファイルには、Shebang行を含めることができます。これを実行し、ファイルに実行可能のマークが付けられている場合、プログラムのように実行できます...ドキュメントのように開くことができます。

一部のアプリケーションでは、この動作を意図的に使用しています。たとえば、VMwareでは、.vmxファイルは仮想マシンを定義します。これらのファイルには実行可能のマークが付いており、VMwareユーティリティでそれらを開くシェバン行があるため、スクリプトのように仮想マシンを「実行」できます。

スクリプトとして実行されないがスクリプトのように振る舞うファイルのシバン行

rmはファイルを削除します。スクリプト言語ではありません。ただし、#!/bin/rmで始まり実行可能とマークされたファイルは実行できます。実行すると、rmが呼び出されて削除されます。

これは、多くの場合、「ファイル自体が削除される」と概念化されます。しかし、ファイルは実際にはまったく実行されていません。これは、上記の.vmxファイルの状況に似ています。

それでも、#!行は単純なコマンド(コマンドライン引数を含む)の実行を容易にするため、この方法でスクリプトを実行できます。 #!/bin/rmよりも洗練された「スクリプト」の簡単な例として、以下を検討してください。

#!/usr/bin/env tee -a

これは、ユーザー入力を対話形式で取得し、行ごとにユーザーにエコーバックし、「スクリプト」ファイルの最後に追加します。

有用?そうでもない。概念的に興味深いですか?完全に!はい。 (幾分。)

概念的に類似したプログラミング/スクリプトの概念(楽しみのためだけに)

99
Eliah Kagan

シバンは、スクリプトの最初の行の最初の2文字として出現する場合、文字の番号記号と感嘆符(たとえば、「#!」)で構成される文字シーケンスです。

* nixオペレーティングシステムでは、Shebangで始まるスクリプトが実行されると、プログラムローダーはスクリプトの最初の行の残りをインタープリターディレクティブとして解析します。代わりに、指定されたインタープリタープログラムが実行され、スクリプトを実行しようとしたときに最初に使用されたパスを引数として渡します。たとえば、スクリプトにパス「path/to/your-script」で名前が付けられ、次の行で始まる場合:

#!/bin/sh

次に、プログラムローダーは、代わりにプログラム「/ bin/sh」を実行するように指示されます。 Bourne Shellまたは互換シェル。最初の引数として「path/to/your-script」を渡します。

したがって、スクリプトにはパス「path/to/python-script」で名前が付けられ、次の行で始まります。

#!/bin/python

ロードされたプログラムは、代わりにプログラム「/ bin/python」を実行するように指示されます。 Pythonインタープリター、「path/to/python-script」を最初の引数として渡します。

つまり、「#」は行をコメントアウトし、文字シーケンス「#!」はスクリプトの最初の行の最初の2文字として出現するという意味は、上記のとおりです。

詳細については、 一部のスクリプトが#!...?で始まる理由 を参照してください。

出典:この回答の一部のセクションは、 Shebang(Unix) on Englishウィキペディア (byウィキペディアの貢献者)。この記事は CC-BY-SA 3.0に基づいてライセンスされています です。AUのユーザーコンテンツと同じであるため、この派生は帰属表示で許可されます。

7
Goran Miskovic

#!は、スクリプトの最初の行の最初の2文字として発生する場合、Shebangと呼ばれます。スクリプトで使用され、実行するインタープリターを示します。 Shebangは、シェルではなく、オペレーティングシステム(カーネル)用です。そのため、コメントとして解釈されません。

礼儀:http://en.wikipedia.org/wiki/Shebang_%28Unix%29

一般に、ファイルが実行可能だが、実際には実行可能(バイナリ)プログラムではなく、そのような行が存在する場合、#!の後に指定されたプログラムスクリプト名とそのすべての引数で開始されます。これらの2つの文字#と!ファイルの最初の2バイトでなければなりません!

詳細情報:http://wiki.bash-hackers.org/scripting/basics#the_Shebang

4
saji89

いいえ、Linuxカーネルのexecシステムコールでのみ使用され、インタープリターによってコメントとして扱われます

Bashで行う場合:

./something

linuxでは、これはパス./somethingexecシステムコールを呼び出します。

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

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

これにより、ファイルの最初のバイトが読み取られ、#!と比較されます。

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

/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に対して人間が読める形式です)。これにより、ELFファイルが読み取られ、メモリに正しく配置され、それを使用して新しいプロセスが開始されます。参照: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861

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

しかし、POSIXがshebangsを指定しているとは思わない: https://unix.stackexchange.com/a/346214/32558 、理由のセクションと「if実行可能スクリプト」の形で言及されているが何かが起こるかもしれないシステムによってサポートされています」。