回答:
#!
行は、スクリプトの実行前に使用され、スクリプトの実行時には無視されます。あなたは、シバンの行と通常のコメントの違いは何かを尋ねています。
始まる行は#!
同じくらいで始まる他の行としてコメントです#
。これが#!
、ファイルの最初の行、またはその他の場所にある場合に当てはまります。#!/bin/sh
効果がありますが、それはインタプリタ自体によって読み込まれていません。
#
はすべてのプログラミング言語でのコメントではありませんが、ご存じのとおり、sh
and を含むBourneスタイルのシェルbash
(およびほとんどの非Bourneスタイルのシェルなどcsh
)でのコメントです。それはですまた、Pythonでのコメント。また、実際にはまったくスクリプトではないさまざまな構成ファイル内のコメントです(など/etc/fstab
)。
シェルスクリプトがで始まるとし#!/bin/sh
ます。これはコメントであり、インタープリター(シェル)は#
文字の後の行のすべてを無視します。
行の目的は#!
、通訳者に情報を提供することではありません。この#!
行の目的は、オペレーティングシステム(またはインタープリターを起動するプロセス)にインタープリターとして使用するものを伝えることです。
たとえば、を実行してスクリプトを実行可能ファイルとして呼び出す./script.sh
と、システムは最初の行を調べて、で始まり#!
、その後にゼロ個以上のスペースが続き、その後にコマンドが続くかどうかを確認します。存在する場合、スクリプト名を引数として使用してそのコマンドを実行します。この例では、実行されます/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のような他のシステムで#!
は、システムによってシェバン行が完全に無視される場合があり、拡張機能がスクリプトを実行するものを決定する場合があります。(これは、スクリプトの拡張機能を提供する必要があるという意味ではありませんが、それが正しい場合、それが正しいはずである理由の1つです。)
#!
コメントを開始するため #
、まさにこの目的を果たすために選ばれました。この#!
行はインタープリターではなくシステム用であり、インタープリターは無視する必要があります。
あなたは(元々)スクリプトに使用すると言い#!/bin/sh
ましbash
た。スクリプトがbash
拡張子をsh
必要としない場合にのみ、スクリプトを実行できる必要があります。sh
は常にへのシンボリックリンクではありませんbash
。多くの場合、上を含む、すべてのリモートでの最近のDebianとUbuntuシステム、sh
へのシンボリックリンクですdash
。
また、(質問の最初のバージョンで、編集する前に)でPythonスクリプトを開始すると言いました#!/bin/sh read by the interpretor
。あなたが文字通りそれを意味するなら、あなたは間違いなくそれをやめるべきです。hello.py
その行で始まる場合、実行./hello.py
は次を実行します:
/bin/sh read by the interpretor hello.py
/bin/sh
read
(by the interpretor hello.py
引数として)と呼ばれるスクリプトを実行しようとしread
ますが、(できれば)検出されず、PythonスクリプトはPythonインタープリターに表示されません。
この間違いを犯しているが、私が説明している問題が発生していない場合は、おそらくインタプリタ(例:)を明示的に指定してPythonスクリプトを呼び出しているpython hello.py
ため、最初の行は無視されます。スクリプトを他の人に配布したり、長い間使用したりすると、それらが機能するために必要であることが明確にならない場合があります。今すぐ修正するのが最善です。または、少なくとも最初の行を完全に削除して./
、エラーメッセージで実行に失敗した場合に意味をなすようにします。
Pythonスクリプトの場合、Pythonインタープリターがどこにあるのか(または、そうなるのか)わかっている場合は#!
、同じ方法で行を記述できます。
#!/usr/bin/python
または、Python 3スクリプトの場合、ほとんどの場合Python 2python3
であるため、を指定する必要があります。python
#!/usr/bin/python3
ただし、問題は/bin/sh
常に存在するはずであり、/bin/bash
ほとんどの場合bash
、OS が付属するシステム上に存在するものの、Pythonはさまざまな場所に存在する可能性があるということです。
したがって、多くのPythonプログラマは代わりにこれを使用します。
#!/usr/bin/env python
(または#!/usr/bin/env python3
Python 3の場合)
これにより、スクリプトは正しい場所env
にあるpython
ことに依存するのではなく、「正しい場所」にあることに依存します。それは良いことです、なぜなら:
env
は、ほぼ常ににあり/usr/bin
ます。python
を実行する方が最初に表示されますPATH
。make run から開始hello.py
します。これは(実質的に)runningと同等です。#!/usr/bin/env python
./hello.py
/usr/bin/env python hello.py
python hello.py
使用できない理由#!python
は次のとおりです。
/
)を指定したい場合。python
現在のディレクトリで実行されます。コマンドにスラッシュが含まれていないときにパスを検索することは、特定のシェルの動作です。シェルスクリプトではないPythonやその他のスクリプト#!/bin/sh ...
に...
は、他のコードがあるところから始まるシェバン行が含まれることがあります。これは、Bourne互換シェル(sh
)を引数付きで呼び出してPythonインタープリターを呼び出す方法があるため、正しい場合があります。(引数の1つにはおそらくpython
。が含まれます。)ただし、ほとんどの目的で#!/usr/bin/env python
は、よりシンプルでエレガントで、希望どおりに機能する可能性が高くなります。
多くのプログラミングおよびスクリプト言語、および他のいくつかのファイル形式は#
、コメントとして使用します。いずれの場合も、言語のファイルは、の後にある最初の行でプログラムを指定することにより、それを引数として使用するプログラムで実行できます#!
。
一部のプログラミング言語で#
は、通常はコメントではありませんが、特殊なケースとして、最初の行がで始まる場合は無視され#!
ます。これにより、行をコメントにしなく#!
ても、構文の使用が容易になります#
。
直感的ではありませんが、最初の行に#!
続いて実行可能ファイルの完全パスが続くファイル形式のファイルには、シェバン行が含まれます。これを実行し、ファイルに実行可能のマークが付けられている場合、プログラムのように実行できます...ドキュメントのように開かれます。
一部のアプリケーションでは、この動作を意図的に使用しています。たとえば、VMwareでは、.vmx
ファイルは仮想マシンを定義します。これらのファイルには実行可能のマークが付いており、VMwareユーティリティで開かれるシェバン行があるため、仮想マシンをスクリプトのように「実行」できます。
rm
ファイルを削除します。スクリプト言語ではありません。ただし、起動#!/bin/rm
して実行可能とマークされたファイルは実行できます。実行すると、そのファイルでrm
呼び出されて削除されます。
これは多くの場合、「ファイルが自動的に削除される」と概念化されます。しかし、ファイルは実際にはまったく実行されていません。これは、上記の.vmx
ファイルの状況に似ています。
それでも、この#!
行は単純なコマンド(コマンドライン引数を含む)の実行を容易にするため、この方法でスクリプトを実行できます。よりも洗練された「スクリプト」の簡単な例として、以下#!/bin/rm
を検討してください。
#!/usr/bin/env tee -a
これは、ユーザー入力を対話形式で取得し、それをユーザーごとに行単位でエコーバックし、「スクリプト」ファイルの最後に追加します。
有用?そうでもない。概念的に興味深いですか?完全に!はい。(幾分。)
一度に複数の言語であるスクリプト/プログラム。たとえば、それがなかったOSのハッシュバング機能をシミュレートします。
(これらのプログラムはポリグロットと呼ばれますが、これはソフトウェア開発における他のポリグロットの意味、異なる部分が異なる言語で書かれているプログラム/プロジェクトと混同しないでください。)
QBasic / QuickBASICのメタコマンド。コード生成用のコンパイラ(コンパイル済みコード用)オプションに信号を送りましたが、コメントの一部であったため、実際のコンパイル/解釈では無視されました。
-x
フラグは何をしますか?
-x
「最初の行をスキップ[...]」の1
代わりに2行目に番号が付けられ、などの代わりに2
3行目2
になり3
ます。このため、このフラグを使用しないでください。;)-x
は、先頭がシェバンのような構文である#
(したがってPythonのコメントではない)非Unix系OSでのスクリプト用です。
perl script.pl
vs. ./script.pl
)、インタプリタはシェバン行を読み取り、などのフラグを解析し-w
ます。ただし、この機能に依存することはお勧めしません。
シバンは、スクリプトの最初の行の最初の2文字として出現する場合、文字の番号記号と感嘆符(「#!」など)で構成される文字シーケンスです。
* nixオペレーティングシステムでは、shebangで始まるスクリプトが実行されると、プログラムローダーはスクリプトの最初の行の残りをインタープリターディレクティブとして解析します。代わりに、指定されたインタープリタープログラムが実行され、スクリプトを実行しようとしたときに最初に使用されたパスが引数として渡されます。たとえば、スクリプトに「path / to / your-script」というパスで名前が付けられ、次の行で始まる場合:
#!/bin/sh
次に、プログラムローダーは、Bourneシェルまたは互換性のあるシェルなどの代わりにプログラム「/ bin / sh」を実行し、最初の引数として「path / to / your-script」を渡すように指示されます。
したがって、スクリプトはパス「path / to / python-script」で名前が付けられ、次の行で始まります。
#!/bin/python
ロードされたプログラムは、代わりにプログラム「/ bin / python」を実行するように指示されます。たとえば、Pythonインタープリターは、「path / to / python-script」を最初の引数として渡します。
つまり、「#」は行をコメントアウトし、文字シーケンスは「#!」です。スクリプトの最初の行の最初の2文字として出現するのは、上記のような意味です。
詳細については、一部のスクリプトが#で始まる理由を参照してください。...?
出典:この回答の一部のセクションは、英語版ウィキペディア(Wikipedia contributors)のShebang(Unix)から(わずかな修正を加えて)派生しています。この記事はCC-BY-SA 3.0の下でライセンスされており、AUのユーザーコンテンツと同じであるため、この派生物は帰属表示で許可されています。
#!
はshebang
、スクリプトの最初の行の最初の2文字として発生するときに呼び出されます。スクリプトで使用され、実行するインタープリターを示します。これshebang
は、シェルではなく、オペレーティングシステム(カーネル)用です。そのため、コメントとして解釈されません。
礼儀: http : //en.wikipedia.org/wiki/Shebang_%28Unix%29
一般に、ファイルが実行可能だが、実際には実行可能(バイナリ)プログラムではなく、そのような行が存在する場合、#!の後に指定されたプログラム スクリプト名とそのすべての引数で開始されます。これらの2つの文字#と!ファイルの最初の2バイトでなければなりません!
詳細情報: http : //wiki.bash-hackers.org/scripting/basics#the_shebang
いいえ、exec
Linuxカーネルのシステムコールでのみ使用され、インタープリターによるコメントとして扱われます
bashで行う場合:
./something
Linuxでは、これはexec
システムコールをpathで呼び出します./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/ls
ELF実行可能ファイルであるの最初の4バイトを読み取って確認します。
head -c 4 "$(which ls)" | hd
出力:
00000000 7f 45 4c 46 |.ELF|
00000004
そのため、カーネルはこれらのバイトを検出すると、ELFファイルを取得し、それをメモリに正しく配置し、それを使用して新しいプロセスを開始します。参照:https : //stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
最後に、このbinfmt_misc
メカニズムを使用して独自のシバンハンドラーを追加できます。たとえば、.jar
ファイルのカスタムハンドラーを追加できます。このメカニズムは、ファイル拡張子によるハンドラーもサポートします。別のアプリケーションは、QEMUを使用して、異なるアーキテクチャの実行可能ファイルを透過的に実行することです。
しかし、POSIXがshebangsを指定しているとは思わない:https ://unix.stackexchange.com/a/346214/32558 、それは根拠のセクションで、「実行可能なスクリプトがシステムでサポートされている場合は何か起こる」。
#include
。そこにも、#
コメントとしての意味はありません。