诸如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示例之间有区别吗?