$PATHの照会は後ろでどのように機能しますか?

$PATHの照会は後ろでどのように機能しますか?

Webには、人々を教えることができる記事/資料が多すぎます。どのようにPATH絶対パスの代わりになどの省略形を使用して、コマンドラインインターフェイスで使用できるように環境変数を設定します。javapython

私が知りたいことはビハインドストーリーコマンドを入力してEnterを押します(例:ブラウザにURLを入力するとどうなりますか?)。

私の推測は次のとおりです。

  1. 読み取りコマンド(正しい引数を取得するための標準入力解析/前処理$@
  2. コマンド検索
  3. コマンドの実行(プログラムの起動、メモリ消費、stdout / stderrからシェルへ)
  4. $PS#関連する環境変数($PROMPTなど)を使用してシミュレータを再レンダリングします。

私が最も気づいているのは、命令の検索です。明らかに、$PATHいくつかの背景機能によって消費され、:/を区切り記号で;区切っていましたが、何が起こっているのでしょうか?ハッシュテーブル(キー:ファイルのデフォルト名、値:ファイルの絶対ディレクトリ名)を使用して、これらのパスまたは他のフックの下にバイナリを保存しますか?

注:現在の環境でコマンドが利用可能であることを確認するために使用できるため、最初はハッシュテーブルであると思いました。[ -z hash [command] ]しかし、使用すると期待どおりに動作しますhash | grep pythonが、出力から何も得られません。which python(メカニズムはシェルによって異なりますが、より深く理解したいです。)

答え1

予想されるように、正確な動作はシェルによって異なりますが、デフォルトの機能レベルはPOSIXによって指定されます。

標準シェルコマンド言語でコマンドを検索して実行する(ほとんどのシェルはこれの親セットを実装します。)多くの場合がありますが、現在はがPATH使用されている場合にのみ興味があります。この場合:

XBD環境変数で説明されているように、PATH環境変数を使用してコマンドを検索する必要があります。

そして

検索が成功した場合:

[...]

シェルは別のユーティリティ環境でこのユーティリティを実行し、次の呼び出しと同じです。execl()機能[...]とパラメータは検索結果のパス名に設定されます。

失敗した場合、実行は失敗し、終了コード127とエラーメッセージが返されます。

特に、この動作はexecvp機能と一致します。すべてのexec*関数は、実行されるプログラムのファイル名、一連の引数(argvプログラムのパラメータになる)、および環境変数のセットを受け入れます。 lookup を使用するバージョンの場合PATHPOSIXは定義します:

議論文書新しいプロセスイメージファイルを識別するパス名を構成するために使用されるパス名[...]このファイルのパスプレフィックスは、環境変数PATHに渡されたディレクトリを検索することによって取得されます。


これPATH の動作は他の場所で定義されます。ように:

この変数は、ファイル名でのみ知られている実行可能ファイルを検索するときに特定の機能とユーティリティーが適用する一連のパスプレフィックスを表す必要があります。接頭辞は <コロン>( ':' ) で区切る必要があります。長さがゼロ以外のプレフィックスがこのファイル名に適用されているときにプレフィックスが<スラッシュ>で終わらない場合は、プレフィックスとファイル名の間に<スラッシュ>を挿入する必要があります。長さゼロのプレフィックスは、現在の作業ディレクトリを表す古い機能です。 2つの隣接する<コロン>文字( "::" )、リストの残りの部分の前の最初の<コロン>、またはリストの残りの部分の後の末尾の<コロン>として表示されます。厳密に互換性のあるアプリケーションは、実際のパス名(例:.)を使用してPATHの現在の作業ディレクトリを表す必要があります。指定された名前と適切な実行権限を持つ実行可能ファイルが見つかるまで、各プレフィックスにファイル名を適用してリストを最初から最後まで検索する必要があります。。探しているパス名に<スラッシュ>が含まれている場合は、パスプレフィックスで検索を実行しないでください。パス名が<slash>で始まると、指定されたパスが解決されます(参照:パス名の確認)。 PATH が設定されていない場合、または null に設定されている場合、パス検索は実装によって定義されます。

内容が少し長くてまとめると次のようになります。

  1. プログラム名/に(スラッシュ、U + 002F SOLIDUS)が含まれている場合はパスと見なされます。普通のファッションをクリックして、このプロセスの残りの部分をスキップします。シェルの場合、この状況は技術的には発生しません(シェルルールがすでにこれを処理しているため)。
  2. の値はPATH各コロンからコンポーネントに分割され、各コンポーネントは左から右に処理されます。特別な(歴史的)ケースとして空でない変数の空の部分は.(現在のディレクトリ)として扱われます。
  3. 各コンポーネントに対して、接続を介してプログラム名が最後に追加され/、その名前のファイルが存在することを確認し、存在する場合は有効な実行(+x)権限も確認します。これらのチェックのいずれかが失敗した場合、プロセスは次のコンポーネントに進みます。それ以外の場合、コマンドはパスを確認して検索を完了します。
  4. コンポーネントが不足すると検索は失敗します。
  5. 何もないかPATH存在しない場合は、好きなようにしてください。

実際のシェルには、照会前に見つかる組み込みコマンドがあり、エイリアスと関数と一緒に表示されることがよくあります。それらはと対話しませんPATHPOSIX はこれに対するいくつかの動作を定義します。、シェルに多くがあるかもしれません。


ほとんどの操作はユーザーが代わりに実行できますが、exec*実際にはシェルは特にキャッシュ目的でこのルックアップ自体を実装できますが、空のキャッシュ動作は似ている必要があります。ここでは、シェルはかなり広い自由度を持ち、コーナーケースではわずかに異なる動作を示します。

あなたが見つけたように、Bashハッシュテーブルの使用以前に見たコマンドのフルパスが記憶され、hashこの機能を使用してテーブルにアクセスできます。コマンドを初めて実行するときに検索を実行し、結果を見つけたらテーブルに追加するため、次回の試行時に検索する必要はありません。

一方、zshではPATH通常、シェルの起動時に完全な検索が行われます。ルックアップテーブルは検索されたすべてのコマンド名で事前入力されているため、通常はランタイムルックアップは必要ありません(新しいコマンドが追加されない限り)。以前に存在しなかったコマンドを完了するためにTabキーを使用しようとすると、これが発生することがわかります。

たとえば、非常に軽いシェルはdashシステムライブラリにできるだけ多くの動作を委任する傾向があり、過去のコマンドパスを覚えていません。

関連情報