web-dev-qa-db-ja.com

プログラムを実行すると、bashはバックグラウンドで何をしますか?

端末の入力は、bashプロセスを介して現在実行中のプログラムにルーティングされていますか、または端末はbashプロセスから「切断」され、新しいプログラムに接続されているため、bashが傍受または干渉することはありませんか?

Bashはバックグラウンドでフリーズし、プログラムが終了するのを待っていますか、それとも何かをしていますか?

ターミナルウィンドウを閉じると、bashにシグナルが送信されますが、bashはフォアグラウンドプロセスにシグナルを送信して両方を閉じますか?または、フォアグラウンドプロセスに信号を送信していますか?

7
Idunnoanymore

端末の入力は、bashプロセスを介して現在実行中のプログラムにルーティングされていますか、または端末はbashプロセスから「切断」され、新しいプログラムに接続されているため、bashが傍受または干渉することはありませんか?

どちらでもない。パイプやリダイレクトのない単純な前景コマンドを想定しています...ユーザーからの入力とユーザーへの出力は、bashを介してルーティングされません。しかし、bashは干渉を防ぐことはできません。bashは干渉を試みないだけです。

プログラムがファイルまたは端末を開くと、読み取りと書き込みに使用するファイル記述子を受け取ります。 子は親の開いているファイル記述子のセットのコピーを継承します。

端末で何かを入力すると、それはstdinを介してプロセスに渡されます。ユーザーに何かを書き込むときは、stdoutまたはstderrに書き込むことによって行います。 stdin、stdout、stderrはすべて予測可能なIDを持つファイル記述子です。POSIX標準では、これらはそれぞれ0 1 2と番号が付けられています。そのため、bashがプログラムを実行すると、最初に fork で子プロセスが作成され、子は同じstdin、stdout、およびstderr FDを自動的に継承します。したがって、子は自動的にまったく同じ端末から読み書きします。

「プログラムの実行」は fork を呼び出し、次に execve を呼び出すことによって行われることに注意してください。パイプとリダイレクトは、fordとexecveの間で dup2 を呼び出してstdin、stdout、およびstderrを置き換えることによって実現されます。

したがって、「プログラム」はbashと同じ端末から直接読み取ることができます。これはbashや同じ端末への読み書きを停止しません。 bashが実際に試みた場合、混乱を引き起こす可能性があります。複数のプロセスが書き込みを行うと、すべてが予測できない順序で書き込まれます。複数のプロセスが読み取ると、一部のバイト(キーストローク)が1つのプロセスに送られ、一部のプロセスが別のプロセスに送られます。

Bashはバックグラウンドでフリーズし、プログラムが終了するのを待っていますか、それとも何かをしていますか?

効果的にフリーズします。より正確には待機します。私が知る限り、明示的に waitpid() またはwait3()(シェルを実行しているUnixによって異なります)を呼び出し、子が終了するのを待ちます。

ターミナルウィンドウを閉じると、bashにシグナルが送信されますが、bashはフォアグラウンドプロセスにシグナルを送信して両方を閉じますか?または、フォアグラウンドプロセスに信号を送信していますか?

申し訳ありませんが、この動作を頭の上で覚えていません。端末[ウィンドウ]を閉じると、何も読み書きしない場合でも、通常、実行中のプロセスが強制終了されると考えています端末の読み取りに基づいており、EOF。端末を閉じると シグナル が発生すると思います。正しい答えが見つかったら、編集します。

一部の子供がキーボード割り込みキーシーケンスを効果的にインターセプトして、bashがそれらを受信できないことを知っています。それが信号を傍受しているのか、端末が信号を一緒に生成できないようにしているのかはわかりません。

3
Philip Couling

尋ねられていない質問は、プロセスを非同期に(&を使用して)開始するとどうなるか、そして&なしでコマンドを入力するのとなぜ違うのかということです。

ここで重要なのが「継承」です。インタラクティブシェルが他に何もしない場合は、プロンプト(PS1変数)を貼り付け、標準入力に読み取りを表示します。起動時にシェルと通信するために作成したストリームにウィンドウマネージャーが書き込むキーストロークがないため、これはハングします。

コマンド名を入力すると、シェルは自身を「フォーク」(複製)し、子はシェルからstdin、stdout、stderrを継承します。次に、子シェルは、コマンドを自分自身にロードするようにカーネルに指示します(「execve」)。

問題は、ウィンドウマネージャーに、同じストリームを読み取る2つのプロセス(元のシェルと子コマンド)があることです。何をすべきか?次に入力するものをだれが読むのですか?

同期「フォアグラウンド」の子の場合、子コマンドはデータを取得する必要があります。そのため、シェルはstdinに読み取りを行いません。代わりに、スリープ状態になり、子が終了し、その終了ステータスが利用可能になると、SIGCHLDによってスリープ解除されます。したがって、2番目の前景の子を開始するように指示する方法はありません。

非同期の「バックグラウンド」の子の場合、子はstdinが切断された状態(/ dev/nullに接続された状態)でフォークされます。 stdoutとstderrは(リダイレクトされない限り)接続されたままであるため、非同期プロセスは引き続き端末に送信できます(ただし、ライン同期はランダムである場合があります)。次に、シェルはプロンプトを表示し、次のコマンド(たとえば、「ジョブ」)を待ちます。他の非同期プロセスを開始したり、一度に1つのコマンドを実行したり、組み込みのシェルコマンドを処理したりできるため、一度に多くのバックグラウンドジョブを実行できます。各非同期の子が終了するときもSIGCHLDを取得し、ステータスの収集、ジョブリストからの削除などを行うことができます。

ターミナルを閉じると、シェルはウィンドウ入力を取得していたストリームでEOFを取得します。それぞれの開始時に設定された内部リストを使用して、すべての子を終了します1。

0
Paul_Pedant