私は bash で呼ばれるシンプルな実行ファイルを実行していますhello
。これはユーザーに入力を問い合わせ、応答を出力します。私は次のように実行します./hello
。
プロンプトの表示とユーザーの応答の入力はどちらも現在のシェルで行われますが、別のシェルで実行されるはずだと思っていました。source を使用して現在のシェルで exe を実行できるため、そう推測しました。
誰かこれがどのように機能するかを説明してくれませんか?
これを調べようとすると、「シェル環境」と「シェルコンテキスト」という用語によく遭遇します。これらは同じものですか?
答え1
現在のシェルの環境については、「シェル環境」と言うことができます。これには、現在の環境変数が含まれます。環境は、開始されたサブプロセス (サブシェルなど) によって継承されます。
「シェル コンテキスト」は一般的には使用されない用語ですが、「プロセス コンテキスト」と同等であると想定しています。シェル スクリプトの場合、これには、シェル環境のほか、現在のシェル変数、ファイル記述子 (標準入力、標準出力、標準エラー、および明示的に開かれたその他のファイル)、シグナル ハンドラー ( とともにインストールされるtrap
) などが含まれます。C プログラムの場合、プロセス コンテキストは の呼び出しでは継承されますfork()
が、後続のexec()
呼び出しでは継承されません ( の呼び出し後は環境のみが存続しますexec()
)。
hello
プログラム (シェル スクリプトであると想定します) を実行すると、hello
スクリプトを実行しているシェルのコンテキストで入力と出力が行われます。これが「現在のシェル」です。入力したシェルは./hello
親シェルであり、hello
その環境を継承します。
内部的には、親シェルはfork()
andexec()
呼び出しを実行して、最終的にスクリプトを実行するシェルを起動しますhello
。
hello
スクリプトが同じことを促しているという事実ターミナルスクリプトを開始した場所とは、スクリプトを実行しているシェルが、その場所の現在のフォアグラウンド プロセスであることを意味します。親シェルはスクリプトの終了を待機しています。終了すると、親シェルは再びターミナルのフォアグラウンド プロセスになります。
source ./hello
またはを使用してスクリプトを開始すると. ./hello
、スクリプトは、そのコマンドを入力したシェルと同じコンテキストで実行されます。つまり、対話型シェルのコンテキストと環境が変更される可能性があります。たとえば、現在の作業ディレクトリを変更したり (環境を変更)、シグナル ハンドラーをインストールしたり (コンテキストを変更) すると、スクリプトの実行が終了した後も、これらの変更は「アクティブ」のままになります。
プログラムがコンパイルされたバイナリである場合hello
、呼び出し元のシェルの環境を継承しますが、コンテキスト (ファイル記述子など) は共有しません。シェル スクリプトではないため、実際にはサブシェルで実行されているわけではありません。親シェルは、シェル スクリプトの場合と同様に、バックグラウンドに移動して、プログラムが終了するのを待ちます。親シェルの観点からは、コンパイルされたバイナリとシェル スクリプトのどちらを開始しても違いはありません。
シェルはバイナリ ファイルの解釈方法を知らないため、コンパイルされたバイナリはsource
または(ドット)で開始されない場合があります。.
この回答には多少の曖昧さがありますが、基本的には正しいと思います。修正や追加が必要な場合は、コメントを残してください (または編集してください)。