(问题经过修订,现在我已经了解了实际发生的事情):
我有一个在后台运行的脚本,定期做一些工作,然后睡30秒:
echo "background script PID: $$"
trap 'echo "Exiting..."' INT EXIT
while true; do
# check for stuff to do, do it
sleep 30
done &
如果我尝试通过kill
或kill INT
删除此脚本,则需要30秒才能响应此信号。
我将在下面回答这个问题,因为我在网上找到了一个很好的解释。
(我原来的,令人尴尬的未经研究的问题)
此问题适用于包含以下陷阱的bash脚本:
trap 'echo "Exiting...">&2; kill $childPID 2>/dev/null; exit 0' \ SIGALRM SIGHUP SIGINT SIGKILL SIGPIPE SIGPROF SIGTERM \ SIGUSR1 SIGUSR2 SIGVTALRM SIGSTKFLT
如果我在前台运行脚本,然后点击 CTRL - C ,它立即获取信号并退出 (不到一秒)。
如果我在后台运行相同的脚本(
&
),并通过它杀死它kill
或kill -INT
,获取信号需要30秒。为什么会这样,我该如何解决?
答案 0 :(得分:3)
正如http://mywiki.wooledge.org/SignalTrap -
中所述“当bash在前台执行外部命令时,它不会处理在前台进程终止之前收到的任何信号” - 并且由于sleep
是外部命令,bash甚至在睡眠之前都看不到信号饰面。
该页面非常好地概述了bash中的信号处理,并解决了这个问题。简而言之,处理这种情况的一种正确方法是将信号发送到进程组,而不仅仅是父进程:
kill -INT -123 # will kill the process group with the ID 123
转到参考页面以获得完整的解释(在我的复制中没有任何意义)。
答案 1 :(得分:2)
可能的原因:在唤醒进程之前,不会发送进程正在休眠时发出的信号。通过命令行启动时,进程不会休眠,因此信号会立即传递。
答案 2 :(得分:0)
@RashaMatt,我无法让read
命令像Greg的wiki上宣传的那样工作。向脚本发送信号只是不会中断读取。我需要这样做:
#!/bin/bash
bail() {
echo "exiting"
kill $readpid
rm -rf $TMPDIR
exit 0
}
sig2() {
echo "doing stuff"
}
echo Shell $$ started.
trap sig2 SIGUSR2
trap bail SIGUSR1 SIGHUP SIGINT SIGQUIT SIGTERM
trap -p
TMPDIR=$(mktemp -p /tmp -d .daemonXXXXXXX)
chmod 700 $TMPDIR
mkfifo $TMPDIR/fifo
chmod 400 $TMPDIR/fifo
while : ; do
read < $TMPDIR/fifo & readpid=$!
wait $readpid
done
...将所需信号发送到Shell $$ started
行显示的shell的pid,并观看兴奋。
wait
更简单,更真实,但是某些操作系统没有sleep infinity
,我想看看Greg的read
示例是如何工作的(它没有“T)。