短い答え
でbash
(とdash
)さまざまな「ジョブ・ステータス」メッセージがシグナルハンドラから表示されますが、明示的なチェックが必要とされていません。このチェックは、新しいプロンプトが提供される前にのみ実行されます。おそらく、ユーザーが新しいコマンドを入力している間にユーザーを混乱させることはありません。
kill
おそらくプロセスがまだ死んでいないため、メッセージが表示された直後のプロンプトの前にメッセージは表示されません-これはkill
シェルの内部コマンドであるため、特に可能性が高い条件であるため、実行が非常に速く、フォークする必要はありません。
killall
代わりに同じ実験を行うと、通常、すぐに「killed」メッセージが表示され、外部コマンドの実行に必要な時間/コンテキストの切り替えなどが原因で、コントロールがシェルに戻る前にプロセスが強制終了されるのに十分な遅延が生じる。
matteo@teokubuntu:~$ dash
$ sleep 60 &
$ ps
PID TTY TIME CMD
4540 pts/3 00:00:00 bash
4811 pts/3 00:00:00 sh
4812 pts/3 00:00:00 sleep
4813 pts/3 00:00:00 ps
$ kill -9 4812
$
[1] + Killed sleep 60
$ sleep 60 &
$ killall sleep
[1] + Terminated sleep 60
$
長い答え
dash
まず最初に、dash
ソースを見てみましdash
た。同じ動作を示し、コードは間違いなくシンプルだからbash
です。
上記のように、ポイントはジョブステータスメッセージがシグナルハンドラー(「通常の」シェル制御フローを中断する可能性がある)から発行されないようですが、実行される明示的なチェック(showjobs(out2, SHOW_CHANGED)
呼び出しdash
)の結果ですREPLループで、ユーザーに新しい入力を要求する前のみ。
したがって、ユーザーの入力を待ってシェルがブロックされた場合、そのようなメッセージは出力されません。
さて、killの直後に実行されたチェックで、プロセスが実際に終了したことが表示されないのはなぜですか?上記で説明したように、おそらく速すぎるためです。kill
はシェルの内部コマンドであるため、実行が非常に高速であり、分岐する必要はありません。したがって、kill
チェックが実行された直後は、プロセスはまだ生きています(少なくとも、まだ強制終了されています)。
bash
予想どおり、のbash
ほうがはるかに複雑なシェルであるため、トリッキーであり、いくつかのgdb
-fuが必要でした。
そのメッセージが発行されるときのバックトレースは次のようなものです
(gdb) bt
#0 pretty_print_job (job_index=job_index@entry=0, format=format@entry=0, stream=0x7ffff7bd01a0 <_IO_2_1_stderr_>) at jobs.c:1630
#1 0x000000000044030a in notify_of_job_status () at jobs.c:3561
#2 notify_of_job_status () at jobs.c:3461
#3 0x0000000000441e97 in notify_and_cleanup () at jobs.c:2664
#4 0x00000000004205e1 in shell_getc (remove_quoted_newline=1) at /Users/chet/src/bash/src/parse.y:2213
#5 shell_getc (remove_quoted_newline=1) at /Users/chet/src/bash/src/parse.y:2159
#6 0x0000000000423316 in read_token (command=<optimized out>) at /Users/chet/src/bash/src/parse.y:2908
#7 read_token (command=0) at /Users/chet/src/bash/src/parse.y:2859
#8 0x00000000004268e4 in yylex () at /Users/chet/src/bash/src/parse.y:2517
#9 yyparse () at y.tab.c:2014
#10 0x000000000041df6a in parse_command () at eval.c:228
#11 0x000000000041e036 in read_command () at eval.c:272
#12 0x000000000041e27f in reader_loop () at eval.c:137
#13 0x000000000041c6fd in main (argc=1, argv=0x7fffffffdf48, env=0x7fffffffdf58) at shell.c:749
死んだジョブと共同をチェックする呼び出し。is notify_of_job_status
(多かれ少なかれshowjobs(..., SHOW_CHANGED)
in と同等dash
); #0-#1はその内部動作に関連しています。6-8はyaccが生成したパーサーコードです。10-12はREPLループです。
ここで興味深い場所は#4、つまりnotify_and_cleanup
呼び出し元です。とはbash
異なりdash
、コマンドラインから読み取られた各文字で終了したジョブをチェックする可能性がありますが、私が見つけたものは次のとおりです:
/* If the shell is interatctive, but not currently printing a prompt
(interactive_shell && interactive == 0), we don't want to print
notifies or cleanup the jobs -- we want to defer it until we do
print the next prompt. */
if (interactive_shell == 0 || SHOULD_PROMPT())
{
#if defined (JOB_CONTROL)
/* This can cause a problem when reading a command as the result
of a trap, when the trap is called from flush_child. This call
had better not cause jobs to disappear from the job table in
that case, or we will have big trouble. */
notify_and_cleanup ();
#else /* !JOB_CONTROL */
cleanup_dead_jobs ();
#endif /* !JOB_CONTROL */
}
そのため、対話モードでは、おそらくユーザーがコマンドを入力するのを妨げないように、新しいプロンプトが表示されるまでチェックを遅らせることが意図されています。の直後に新しいプロンプトを表示するときに、チェックがデッドプロセスを見つけない理由についてはkill
、前の説明が保持されます(プロセスはまだデッドではありません)。
pid="$(sh -c 'cat "$fileName" |less & echo ${!}')"
しかし、あまり表示されません