シェルスクリプトがで始まる場合#!
、その最初の行はシェルに関する限りコメントです。ただし、最初の2文字はシステムの別の部分、つまりカーネルにとって意味があります。この2つのキャラクター#!
はシバンと呼ばれます。シバンの役割を理解するには、プログラムの実行方法を理解する必要があります。
ファイルからプログラムを実行するには、カーネルからのアクションが必要です。これは、execve
システムコールの一部として行われます。カーネルは、ファイルのアクセス許可を確認し、呼び出しプロセスで現在実行中の実行可能ファイルに関連付けられているリソース(メモリなど)を解放し、新しい実行可能ファイルにリソースを割り当て、新しいプログラムに制御を転送する必要があります私は言及しません)。execve
システムコールは、現在実行中のプロセスのコードを置き換えます。fork
新しいプロセスを作成するための別のシステムコールがあります。
これを行うには、カーネルが実行可能ファイルの形式をサポートする必要があります。このファイルには、カーネルが理解できるように編成されたマシンコードが含まれている必要があります。シェルスクリプトにはマシンコードが含まれていないため、この方法で実行することはできません。
shebangメカニズムにより、カーネルはコードを別のプログラムに解釈するタスクを延期できます。カーネルは、実行可能ファイルがで始まることを認識#!
すると、次の数文字を読み取り、ファイルの最初の行(先頭#!
とオプションのスペースを除く)を別のファイルへのパスとして解釈します(引数についてはここでは説明しません) )。カーネルがファイルを実行するように指示さ/my/script
れ、ファイルが行#!/some/interpreter
で始まることがわかると、カーネルは/some/interpreter
引数で実行されます/my/script
。その後、それが実行するスクリプトファイルであるかどう/some/interpreter
かを判断し/my/script
ます。
ファイルにカーネルが理解できる形式のネイティブコードが含まれておらず、シバンで始まらない場合はどうなりますか?それでは、ファイルは実行可能ではなく、execve
システムコールはエラーコードENOEXEC
(実行可能形式エラー)で失敗します。
これで話は終わりかもしれませんが、ほとんどのシェルはフォールバック機能を実装しています。カーネルがを返すENOEXEC
場合、シェルはファイルのコンテンツを調べ、ファイルがシェルスクリプトのように見えるかどうかを確認します。シェルは、ファイルがシェルスクリプトのように見えると判断した場合、それ自体を実行します。これを行う方法の詳細は、シェルによって異なります。ps $$
スクリプトに追加することで、何が起こっているかを見ることができます。さらにstrace -p1234 -f -eprocess
、1234がシェルのPIDであるプロセスを見ると、何が起こっているのかを確認できます。
bashでは、このフォールバックメカニズムはを呼び出すことで実装されますがfork
、ではありませんexecve
。子bashプロセスは、内部状態を自動的にクリアし、新しいスクリプトファイルを開いて実行します。したがって、スクリプトを実行するプロセスは、元のbashコードイメージと、bashを最初に起動したときに渡された元のコマンドライン引数を引き続き使用しています。ATT kshは同じように動作します。
% bash --norc
bash-4.3$ ./foo.sh
PID TTY STAT TIME COMMAND
21913 pts/2 S+ 0:00 bash --norc
対照的に、ダッシュは、引数として渡されたスクリプトへのパスでENOEXEC
呼び出し/bin/sh
て反応します。つまり、ダッシュからシバンレススクリプトを実行すると、スクリプトにのようなシバン行が含まれているかのように動作し#!/bin/sh
ます。Mkshとzshは同じように動作します。
% dash
$ ./foo.sh
PID TTY STAT TIME COMMAND
21427 pts/2 S+ 0:00 /bin/sh ./foo.sh