简短答案
在bash
(和dash
)中,各种“作业状态”消息不会从信号处理程序中显示出来,但需要进行明确的检查。仅在提供新提示之前执行此检查,可能不会打扰用户输入新命令的过程。
该消息不会在显示之后的提示之前kill
显示,可能是因为进程尚未结束-这是特别可能的情况,因为它kill
是Shell的内部命令,因此执行速度非常快,不需要派生。
killall
相反,使用进行相同的实验通常会立即产生“ killed”消息,这表明时间/上下文切换/执行外部命令所需的任何时间都会导致足够长的延迟,以使进程在控制权返回到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
$
长答案
dash
首先,我查看了dash
来源,因为dash
表现出相同的行为,并且代码肯定比更加简单bash
。
如上所述,重点似乎是作业状态消息不是从信号处理程序发出的(这可能会中断“正常” shell控制流),但是它们是显式检查的结果( showjobs(out2, SHOW_CHANGED)
in调用dash
)的结果仅在从用户请求新输入之前,在REPL循环中。
因此,如果外壳被阻塞以等待用户输入,则不会发出任何此类消息。
现在,为什么在终止之后不执行检查就表明进程实际上已终止?如上所述,可能是因为它太快了。kill
是Shell的内部命令,因此执行速度非常快,不需要派生,因此,在kill
执行检查后立即执行,该过程仍然有效(或者至少仍被终止)。
bash
不出所料,bash
作为一个复杂得多的shell,它比较棘手,需要一些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)
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 ${!}')"
但不会少出现