Resposta curta
Em bash
(e dash
) as várias mensagens de "status do trabalho" não são exibidas nos manipuladores de sinal, mas requerem uma verificação explícita. Essa verificação é realizada apenas antes que um novo prompt seja fornecido, provavelmente para não incomodar o usuário enquanto ele estiver digitando um novo comando.
A mensagem não é mostrada antes do prompt após a kill
exibição provavelmente porque o processo ainda não está morto - essa é uma condição particularmente provável, pois kill
é um comando interno do shell, portanto, é muito rápido de executar e não precisa de bifurcação.
Em killall
vez disso, fazer o mesmo experimento normalmente gera a mensagem "morto" imediatamente, assine que o tempo / contexto alterna / o que for necessário para executar um comando externo causa um atraso longo o suficiente para que o processo seja morto antes que o controle retorne ao shell .
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
$
Resposta longa
dash
Antes de tudo, observei as dash
fontes, pois dash
exibe o mesmo comportamento e o código é certamente mais simples que bash
.
Como dito acima, o ponto parece ser que as mensagens de status da tarefa não são emitidas de um manipulador de sinal (que pode interromper o fluxo de controle de shell "normal"), mas são a consequência de uma verificação explícita (uma showjobs(out2, SHOW_CHANGED)
chamada dash
) realizada somente antes de solicitar nova entrada do usuário, no loop REPL.
Portanto, se o shell estiver bloqueado aguardando a entrada do usuário, nenhuma mensagem será emitida.
Agora, por que a verificação realizada logo após a matança mostra que o processo foi realmente encerrado? Como explicado acima, provavelmente porque é muito rápido. kill
é um comando interno do shell, por isso é muito rápido de executar e não precisa de bifurcação, portanto, quando imediatamente após kill
a verificação é realizada, o processo ainda está ativo (ou, pelo menos, ainda está sendo morto).
bash
Como esperado, bash
sendo um shell muito mais complexo, era mais complicado e exigia um pouco de gdb
-fu.
O retorno para quando essa mensagem é emitida é algo como
(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
A chamada que verifica se há trabalhos mortos e companhia. é notify_of_job_status
(é mais ou menos o equivalente a showjobs(..., SHOW_CHANGED)
in dash
); # 0- # 1 estão relacionados ao seu trabalho interno; 6-8 é o código do analisador gerado pelo yacc; 10-12 é o loop REPL.
O lugar interessante aqui é o número 4, ou seja, de onde a notify_and_cleanup
chamada chega. Parece que bash
, ao contrário dash
, pode verificar trabalhos terminados em cada caractere lido na linha de comando, mas eis o que eu encontrei:
/* 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 */
}
Portanto, no modo interativo, é intencional adiar a verificação até que um novo prompt seja fornecido, provavelmente não perturbe o usuário digitando comandos. Quanto ao motivo pelo qual a verificação não identifica o processo morto ao exibir o novo prompt imediatamente após kill
, a explicação anterior é válida (o processo ainda não está morto).
pid="$(sh -c 'cat "$fileName" |less & echo ${!}')"
mas menos não aparecerá