如果我有以下 shell 脚本
sleep 30s
Ctrl+C当 shell 脚本运行时,我点击了它,它sleep
随之消失。
如果我有以下 shell 脚本
sleep 30s &
wait
Ctrl+C当 shell 脚本运行时,我点击了,sleep
继续,现在父级为 1。
这是为什么? bash 不会传播Ctrl+C给所有孩子吗?
编辑:如果我有以下脚本
/usr/bin/Xvfb :18.0 -ac -screen 0 1180x980x24 &
wait
我正在生成一个程序,这次Ctrl+C在主进程上Xvfb
也杀死了该进程。
那么Xvfb
与睡眠有何不同/为何不同?
在一些情况下,我发现它们被 回收init
,而有些情况下它们会死亡。为什么 sleep 会被 init 回收?为什么会Xvfb
死亡?
答案1
太长;博士;该Xvfb
进程设置了一个信号处理程序,SIGINT
并在收到此类信号时退出,但进程sleep
没有这样做,因此它继承了“忽略”状态,因为SIGINT
它是由在执行二进制文件之前运行脚本的 shell 设置的sleep
。
运行 shell 脚本时,作业控制将关闭,后台进程(以 开头的进程&
)仅在同一进程组中运行,并将SIGINT
和SIGQUIT
设置为SIG_IGN
(忽略),并且其标准输入从 重定向/dev/null
。
这是由标准:
如果在 shell 执行异步列表时禁用作业控制(请参阅 set -m 的说明),则列表中的命令将从 shell 继承 SIGINT 和 SIGQUIT 信号的忽略 (SIG_IGN) 信号操作。
如果信号处理设置为(忽略),则该状态将通过和SIG_IGN
继承fork()
execve()
:
在调用过程映像中设置为默认操作 (SIG_DFL) 的信号应在新过程映像中设置为默认操作。除 SIGCHLD 外,调用过程映像设置为忽略的信号 (SIG_IGN) 应设置为由新过程映像忽略。
答案2
来自bash 手册页:
后台进程是指进程组ID与终端进程组ID不同的进程;此类进程不受键盘生成信号的影响
你可以用不同的方式来处理这个问题;首先,终止列出的作业:
#!/bin/bash
trap 'kill $(jobs -p)' INT
sleep 30s &
wait
或者,向同一进程组中的所有进程发送终止命令:
#!/bin/bash
trap 'kill 0' INT
sleep 30s &
wait
答案3
Bash 不会将 SIGINT 或 SIGTERM 等信号转发给当前正在等待的进程。
一种常见的解决方法是执行 trap wait 等待,如以下示例所示:
int_handler()
{
kill -TERM "${child_pid}" > /dev/null 2>&1
}
trap 'int_handler' INT
echo "Sleeping ... "
sleep 200 &
child_pid=$!
wait ${child_pid} > /dev/null 2>&1
trap - INT
wait ${child_pid} > /dev/null 2>&1