诸如Ctrl+的信号键C将信号发送到前台进程组中的所有进程。
在典型情况下,过程组是管道。例如,在中head <somefile | sort
,进程运行head
和进程运行sort
与外壳位于同一个进程组中,因此它们都接收信号。在后台(somecommand &
)中运行作业时,该作业位于其自己的进程组中,因此按Ctrl+ C不会对其产生影响。
该timeout
程序将自己置于自己的进程组中。从源代码:
/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
then we would need to worry about foreground and background groups
and propagating signals between them. */
setpgid (0, 0);
发生超时时,timeout
将通过简单的方法来杀死它所属的进程组。由于它已将自己置于单独的进程组中,因此其父进程将不在该组中。在此处使用进程组可确保如果子应用程序派生到多个进程中,则其所有进程都将接收信号。
当您timeout
直接在命令行上运行并按Ctrl+时C,timeout
子进程和子进程都将接收到结果SIGINT ,而不是作为timeout
父进程的交互式shell 会接收到此消息。当timeout
从脚本调用时,只有运行脚本的shell会接收到该信号:timeout
由于它在不同的进程组中,所以没有得到它。
您可以使用trap
内置脚本在shell脚本中设置信号处理程序。不幸的是,这不是那么简单。考虑一下:
#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date
如果您在2秒钟后按Ctrl+ C,则仍会等待5秒钟,然后打印“ Interrupted”消息。这是因为在前台作业处于活动状态时,shell拒绝运行陷阱代码。
要解决此问题,请在后台运行作业。在信号处理程序中,调用kill
以将信号中继到timeout
过程组。
#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid
bg
的fg
命令。无论如何,您的1d和3d示例之间有区别吗?