インタプリタへのパスを指定する代わりに、インタプリタの名前があり、シェルが$ PATHを介してそれを見つけられるようにするシェバンを持つことは可能ですか?
そうでない場合、理由はありますか?
インタプリタへのパスを指定する代わりに、インタプリタの名前があり、シェルが$ PATHを介してそれを見つけられるようにするシェバンを持つことは可能ですか?
そうでない場合、理由はありますか?
回答:
PATHルックアップは、一般的な環境変数と同様に、ユーザー空間の標準Cライブラリの機能です。カーネルは、呼び出し元からexecve
新しいプロセスに環境を渡す場合を除いて、環境変数を認識しません。
カーネルは、パスexecve
(execvp
PATHルックアップを実行するなどのラッパー関数に依存)またはシバン(execve
コールを内部的に再ルーティングする)のパスに対して解釈を実行しません。そのため、絶対パスをシェバンに入れる必要があります¹。元シェバングの実装では、わずか数行のコードであり、それはかなり以来、拡張されていません。
Unixの最初のバージョンでは、シェルは、スクリプトを呼び出していることに気付いたときに、それ自体を呼び出す作業を行いました。Shebangはいくつかの理由でカーネルに追加されました(Dennis Ritchieによる理論的根拠の要約:
パスレスシェバンでは、環境変数とプロセスにアクセスするためにカーネルを強化するかPATH
、PATHルックアップを実行するユーザースペースプログラムをカーネルに実行させる必要があります。最初の方法では、不均衡な量の複雑さをカーネルに追加する必要があります。2番目の方法は、#!/usr/bin/env
シバンですでに可能です。
¹ 相対パスを指定すると、プロセスの現在のディレクトリ(スクリプトを含むディレクトリではなく)に対して相対的に解釈されるため、シバンではほとんど役に立ちません。
execve
シバン内に相対パスを持つことはほとんど意味がありませんが、カーネルはシバン内またはシバン内に絶対パスを必要としません。
/lib64/ld-linux-x86-64.so.2
(ldd
出力を参照)。Linuxでは完全に汎用的になっています。binfmt
サポート(2.1.43以降)により、インタープリターパス/マジックナンバーまたはファイル拡張子のペアを登録できます。あなたはPE32持つことができる.exe
の呼び出しをwine
あなたがそれらを実行すると、JavaクラスとJARファイルを呼び出すjava
などなど、
目に見える以上のことが起こっています。#!
行はUnixまたはLinuxカーネルによって解釈されますが、#!
シェルの側面ではありません。これはPATH
、カーネルが実行する内容を決定する時点では実際には存在しないことを意味します。
どの実行可能ファイルを実行するか、またはperl
ポータブルな方法などで呼び出すかを知らない場合に対処する最も一般的な方法は、を使用すること#!/usr/bin/env perl
です。カーネルが実行され/usr/bin/env
、PATH
環境変数を継承します。env
発見(この例では)perl
中PATH
と使用execve(2)
を実行するためにカーネルを取得するためにシステムコールをperl
実行します。
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0
フルパスへの変換はシェルによって行われます(より一般的にはユーザー空間で)。カーネルは、直接アクセスできるファイル名/パスを期待しています。
システムがPATH変数を調べて実行可能ファイルを検索するようにしたい場合は、shebangをとして書き換えることができます#!/usr/bin/env EXEC
。
ただし、この場合も検索を行うのはカーネルではありません。
strace
されています(/usr/bin/strace
ある時点で変換されます)。