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


66

ではbashまたはsh、Iで始まる何かが推測#されたコメント

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

#!/bin/bash

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

#!/bin/python

これは、#それ自体がコメントで#!はなく、コメントであることを意味しますか?


1
そして、Apparmorプロファイルを見ると、が表示されます#include。そこにも、#コメントとしての意味はありません。

4
@ vasa1しかし、シェルスクリプトの冒頭にあるハッシュバングの行についてあまり評価されない重要な点は、コメントであるということです
エリアケイガン

回答:


100

この#!行は、スクリプトの実行に使用さ、スクリプトの実行時には無視されます。

あなたは、シバンの行と通常のコメントの違いは何かを尋ねています。

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

#はすべてのプログラミング言語でのコメントではありませんが、ご存じのとおり、shand を含む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つです。)

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

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

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

PythonスクリプトのShebangライン

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

/bin/sh read by the interpretor hello.py

/bin/shreadby 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 python3Python 3の場合)

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

  • envは、ほぼ常ににあり/usr/binます。
  • ほとんどのシステムでは、スクリプトpython 実行する方が最初に表示されますPATH。make run から開始hello.pyします。これは(実質的に)runningと同等です。#!/usr/bin/env python./hello.py/usr/bin/env python hello.pypython 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

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

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

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


@Rinzwind Thx!(ところで、もしあなたが疑問に思っているなら、この答えは他の場所からは生まれていません。)
エリアカガン

@Rinzwind心配しないでください、1時間後に8回のアップ投票があり、さらに
上がる

1
常に無視される場合、Pythons -xフラグは何をしますか?
ゲリット

4
@gerrit良い質問です。インタプリタ/コンパイラが行番号付きのメッセージを報告する言語では、コメントの内容は無視されますが、コメント行は引き続きカウントされます。コード行の前にコメントまたは空白行を追加しても、そのコード行の行番号は増加します。-x「最初の行をスキップ[...]」の1代わりに2行目に番号が付けられ、などの代わりに23行目2になり3ます。このため、このフラグを使用しないでください。;)-xは、先頭がシェバンのような構文である#(したがってPythonのコメントではない)非Unix系OSでのスクリプト用です。
エリアケイガン

4
Perlでは、インタプリタが直接起動される場合(perl script.plvs. ./script.pl)、インタプリタシェバン行を読み取り、などのフラグを解析し-wます。ただし、この機能に依存することはお勧めしません。
ハーミングモニカを停止

7

シバンは、スクリプトの最初の行の最初の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のユーザーコンテンツと同じであるため、この派生物は帰属表示で許可されています。


4

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

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

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

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


0

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

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/lsELF実行可能ファイルであるの最初の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 、それは根拠のセクションで、「実行可能なスクリプトがシステムでサポートされている場合は何か起こる」。

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