プロセスを終了した後にbashに「終了しました」と表示されるのはなぜですか?

プロセスを終了した後にbashに「終了しました」と表示されるのはなぜですか?

これは私が理解したい行動です。

$ 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ます(プロセスはまだ死んでいません)。

おすすめ記事