Короткий ответ
В bash
(и dash
) различные сообщения «статус работы» не отображаются из обработчиков сигналов, но требуют явной проверки. Эта проверка выполняется только перед предоставлением нового приглашения, вероятно, чтобы не беспокоить пользователя, пока он вводит новую команду.
Сообщение не отображается непосредственно перед приглашением после того, kill
как отображается, вероятно, потому, что процесс еще не завершен - это особенно вероятное условие, поскольку kill
это внутренняя команда оболочки, поэтому она очень быстро выполняется и не требует разветвления.
Выполнение того же эксперимента killall
вместо этого обычно приводит к немедленному выводу сообщения «kill», что означает, что переключение времени / контекста / все, что требуется для выполнения внешней команды, вызывает задержку, достаточную для того, чтобы процесс был убит, прежде чем элемент управления вернется в оболочку ,
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
Звонок, который проверяет на мертвые рабочие места & co. есть notify_of_job_status
(это более или менее эквивалентно showjobs(..., SHOW_CHANGED)
в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 ${!}')"
но меньше не появятся