web-dev-qa-db-ja.com

なぜシバンラインが常に最初のラインである必要があるのですか?

私は以下のような簡単なPerlスクリプトを持っています:

#!/usr/bin/Perl

use strict;
use warnings;

print "hello world!\n";

このスクリプトは次のように実行できます。

>temp.pl
hello world!
>

このようなコメントを追加すると:

#this script is just for test
#the Shebang
#!/usr/bin/Perl

use strict;
use warnings;

print "hello world!\n";

実行しようとすると、次のような出力が表示されます。

> temp.pl
use: Command not found.
use: Command not found.
print: Command not found.
> 

ここでのポイントは、何があっても、シバンラインは常に一番上にあるべきだということです。誰かが理由を説明できますか?

20
Vijay

Shebangは、実行可能ファイルの先頭にある2バイトを調べるkernelによって解釈されるため、最初の行である必要があります。これらが#!の場合、行の残りの部分は、実行する実行可能ファイルとして解釈され、そのプログラムで使用可能なスクリプトファイルを使用します。 (詳細は若干異なりますが、それが写真です)。

カーネルは最初の2文字のみを調べ、それ以降の行の概念がないため、1行目にハッシュバンを配置する必要があります。

カーネルが#!whateverで始まるファイルを実行できない場合はどうなりますか?最後の手段として、実行可能ファイルをフォークしようとし、カーネルからプログラムを実行できないことを通知されたシェルは、ファイルの内容をシェルスクリプトとして解釈しようとします。シェルはPerlではないため、実行しようとした場合とまったく同じように、多数のエラーが発生します。

 sh < temp.pl
29
Jens

詳細に説明されている上記の説明に加えて、 ここここここ#!とについていくつかの特別なことがありますまだ言及されていないPerl。

Perlは#!行を読み取り、2つのことを行います。まず、パスがPerlのように見えない場合は、それを使用してプログラムを再実行します。例えば...

#!/bin/sh

echo "Hello world!"

Perl /path/to/that/programとして実行すると、正しく実行されます。 Perlがこれを行う歴史的な理由はわかりませんが、Test :: Harnessを使用して複数の言語をテストする場合に便利です。

2つ目は、Perlが#!行でスイッチを見つけて、コマンドラインにあるかのように適用することです。これが、#!/usr/bin/Perl -wが警告をオンにするために機能する理由です。

Shebang処理の他の部分とは異なり、これはすべてUnixではなくPerl内で行われるため、Windowsに移植可能であることに言及する価値があります。

もう1つのPerl + Shebangの注意点は、多くのPerlプログラムの上部に見られるかもしれないこの狂気です。

#!/usr/bin/Perl

eval 'exec /usr/bin/Perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some Shell

非常に、非常に、非常に古いシステムでは、#!が機能せず、Perlプログラムがシェルによって実行されることがあります。 evalは、シェルに最初にPerlでファイルを再実行させる。シェルステートメントは改行で終了するため、if 0は表示されません。 Perlはif 0を認識しているため、evalを実行しません。 PerlとShellの両方に、構文的に同等のeval演算子があり、ハックを機能させます。

7
Schwern

最初の行である必要があるだけでなく、文字#!はファイルの最初の2バイトである必要があります。これがスクリプトを実行できることは、OSではなくシェルの機能であり、特定のスクリプト言語に固有のものではありません。

システムは、.../path/to/bin/programのようなものを使用するか、PATHを介した類似のルートを介してファイルの内容を実行するように指示されると、ファイルの最初の数バイトを調べて「マジックナンバー」を探します。ファイルの種類を明らかにします(file(1)コマンドを使用してそのプロセスを確認できます)。コンパイルされたバイナリの場合は、適切な方法でロードして実行し、最初の2バイトが#!の場合は、「Shebang-hack」を実行します。

'Shebang-hack'は、一部のシェル(実際には基本的にすべてですが、要件ではなく慣例です)で採用されている特殊なケースであり、シェルは改行までの残りのバイトを読み取り、これらをファイル名として解釈します。 、次にそのファイルを実行して、現在のファイルの残りを入力として与えます。さらに、おそらく 他の場所 について読むことができるいくつかの詳細。

いくつかの(バージョンの)シェルは非常に長い最初の行を許可し、いくつかは短い行のみを許可します。複数の引数を許可するものもあれば、1つだけを許可するものもあります。

ファイルが#!で始まっていないが、テキストのように見える場合、一部のシェルはヒューリスティックにファイルを実行しようとします。 Csh(私が正しく思い出せば)は、それがcshスクリプトであることにパントを取ります。最初の行が空白の場合、いくつかのシェルの動作に関係する複雑で難解なケースがあります。これは、寿命が短すぎて覚えられません。

Sven Mascheckの#!ページ には、興味深く広範囲にわたる詳細(そして、私の記憶と一致するという意味で正確な詳細)があります。

6
Norman Gray

少なくともPOSIX準拠のシステムでは、Shebangを使用して、実行可能ビットが設定されたテキストファイルをどう処理するかを実行可能ローダーに指示します。

ローダーはバイナリファイルをどう処理するかを知っています。それらは「マジックナンバー」で始まり、通常は最近ELFに関連しています。

一方、シバンがないテキストファイルは、マシンで使用可能なPOSIX準拠のシェルによって実行されるため、次のシェルエラーメッセージが表示されます。

use: Command not found.
use: Command not found.
print: Command not found.

実行可能ファイルがPOSIX準拠のシェルによって解釈されない場合は、使用するインタープリターをローダーに指示する必要があります。 Windowsのような他のOSはそれを理解するためにファイル拡張子を選びますが、Unixはこの特定のケースでは拡張子を使用または気にしません。使用するのは、使用するコマンドインタープリターを示す最初の行のShebangです。唯一の欠点は、スクリプト言語がこの最初の行を無視する必要があることです。うまくいけば、これは#は、ほとんどのスクリプト言語のコメント行プレフィックスです。

一般に信じられていることですが、ポータブルスクリプトにはシバンを含めるべきではありません。特に #!/bin/shはお勧めしません。

0
jlliagre