为什么我的bash脚本在后台运行时需要很长时间来响应kill?

时间:2013-12-11 07:47:00

标签: bash signals kill bash-trap

(问题经过修订,现在我已经了解了实际发生的事情)

我有一个在后台运行的脚本,定期做一些工作,然后睡30秒:

echo "background script PID: $$"
trap 'echo "Exiting..."' INT EXIT
while true; do
    # check for stuff to do, do it
    sleep 30
done &

如果我尝试通过killkill 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 ,它立即获取信号并退出   (不到一秒)。

     

如果我在后台运行相同的脚本(&),并通过它杀死它   killkill -INT,获取信号需要30秒。

     

为什么会这样,我该如何解决?

3 个答案:

答案 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,并观看兴奋。

睡觉的{p> wait更简单,更真实,但是某些操作系统没有sleep infinity,我想看看Greg的read示例是如何工作的(它没有“T)。