これは私が理解したい行動です。
$ ps
PID TTY TIME CMD
392 ttys000 0:00.20 -bash
4268 ttys000 0:00.00 xargs
$ kill 4268
$ ps
PID TTY TIME CMD
392 ttys000 0:00.20 -bash
[1]+ Terminated: 15 xargs
$ ps
PID TTY TIME CMD
392 ttys000 0:00.21 -bash
[1]+ Terminated: 15 xargs
プロセスが終了したときに表示されず、プロセスが終了した後に表示されるのはなぜですか?
私はMac OS X 10.7.5でbashを使用しています。
ベストアンサー1
短い答え
bash
(および)では、dash
さまざまな「ジョブステータス」メッセージがシグナルハンドラに表示されませんが、明示的なチェックが必要です。この確認は、新しいプロンプトを入力する前にのみ実行され、ユーザーが新しいコマンドを入力している間にユーザーを邪魔しないことがあります。
メッセージは、kill
表示後にプロンプトの前に表示されません。それはおそらく、まだプロセスが終了していないからです。これは特にkill
シェルの内部コマンドなので、非常に速く実行され、フォークが不要なので、そうする可能性が高くなります。
対照的に、.exeを使用して同じ実験を実行すると、通常はkillall
「終了しました」というメッセージがすぐに生成されます。これは、時間/コンテキストスイッチ/外部コマンドを実行するために必要なすべてが、制御が返される前にプロセスを終了するのに十分な長い遅延があることを示します。シェル。
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
チェックを実行した直後にプロセスはまだ生きています(または少なくともまだ終了しています)。
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 ( innotify_of_job_status
とほぼ同じ ) #0-#1 は内部動作に関連しており、6-8 は yacc 生成パーサコードです。showjobs(..., SHOW_CHANGED)
dash
ここで興味深いのは、notify_and_cleanup
呼び出しが発生する#4です。これとは異なり、コマンドラインから読み取ったすべての文字で終了した操作を確認することは可能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
ます(プロセスはまだ死んでいません)。