コマンドの実行に関する簡単な質問がありますls
。インターネットで調査した内容に基づいて、次のことを理解しています。
コマンドを入力すると、シェルは
ls
コマンドを解釈します。その後、シェルプロセスは子プロセスを分岐して生成し、親プロセス(シェル)はシステムコールを実行し、
wait()
子プロセスが終了するまで効果的にスリープモードになります。子プロセスは、開いているすべてのファイル記述子と環境を継承します。
サブプロセス(シェル)はプログラムの一部を実行し、バイナリファイルがディスク
exec()
(ファイルシステム)からロードされ、ls
同じls
プロセスで実行されるようにします。ls
プログラムの実行が完了するとexit()
呼び出され、カーネルは子プロセスが終了したことを示すシグナルを親プロセスに送信します。
私の疑いは、ls
タスクが完了したら結果を親プロセスに送り返すのか、それとも出力を画面に表示するのですか?出力を親項目に戻す場合はpipe()
暗黙的に使用されますか?
答え1
ls
出力すべきことを出力します標準出力。これを行うには、write
次のシステムコールを呼び出します。
write(1, "file1 file2...\n", 16)
(または同様の関数を呼び出すか、最終的にシステムコールを実行する可能性が高いlibc
)printf
fwrite
write()
ファイル記述子1
(規則に従ってstdout)がすでに開いていて何かを指しているとします。実際にls
ファイル記述子1が端末などを指していることを確認してください。端末を指していない場合は、端末を指します。
write(1, "file1\nfile2...\n", 15)
つまり、出力が端末に送信されない場合は、1行に1行ずつファイルに書き込みます。
あなたが書くとき:
ls file1 file2
ls
ファイル記述子 1 は、シェルの fd 1 と同じリソースを指します (たとえば、 で始まる対話型シェルの場合、xterm
xterm によって制御される擬似端末装置を指します)。シェルは特別な操作を行わずに継承され、fork
そのO_CLOEXEC
フラグは通常ファイル記述子に対して設定されていないためexecve
。
あなたが書いている場合:
var=$(ls file1 file2)
シェルはパイプを作成し、サブプロセスのfd 1をパイプの書き込み端に割り当て、パイプのもう一方の端を読み取り、変数を埋めますvar
。
終了時に魔法のように実行されるのではなく、プロセス操作の一部として実行されます。これはシェルの他の活動とは無関係です。一部のリソース(たとえば、端末)に1つの接続がls
ある別のプロセスであり、シェルは実行中です。fd
waitpid()
ただし、stdoutが端末でない場合は、出力をバッファリングして十分なデータ(十分なキロバイト)を蓄積した場合、または出力を閉じるか終了するときにのみls
呼び出されることがわかります。write()
したがって、終了時に完了を見つけることができますが、write
これらのI / Oライブラリが完了するバッファの一部としてのみ可能です。flushing
答え2
答え3
厳密に言えばどちらもありません親と子の実際の出力は画面に移動し、代わりにオペレーティングシステムカーネル(特にtty
ドライバ)が出力を実行します。プロセスはファイル記述子にのみデータを送信します。
strace -f /bin/bash "ls;exit"
また、以下のように、ファイル記述子に誰が何を書いているのかを明確に推測しないでください(BASHは分岐しないことで「-c ls」を最適化するようで、後で「;exit」を使用しました)。 (bashclone
はnoを使用しますfork
):
...
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f9814b5d9d0) = 30029
Process 30029 attached
[pid 30028] rt_sigprocmask(SIG_SETMASK, [], <unfinished ...>
[pid 30029] rt_sigprocmask(SIG_SETMASK, [], <unfinished ...>
...
[pid 30028] wait4(-1, <unfinished ...>
...
[pid 30029] execve("/usr/bin/ls", ["ls"], [/* 72 vars */]) = 0
...
[pid 30029] write(1, "00708022-PTF-26962\nCASE00280714\n"..., 18500708022-PTF-26962) = 185
...
[pid 30029] exit_group(0) = ?
[pid 30029] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 30029
...
したがって、実際にはPID 30029(サブプロセス)がファイル名を書き、終了してから親プロセスが続くことがわかります(以降wait4
)。
答え4
成功すると、exec(3)
それを呼び出したプログラムはもう存在しません。プログラムエド(program ed)に置き換えられましたexec
。実行する新しいプログラムは、元のプログラム、特に開いているファイルの環境を継承します。