Why does my bash script take so long to respond to kill when it runs in the background?

拈花ヽ惹草 提交于 2019-12-10 21:08:13

问题


(Question revised, now that I understand more about what's actually happening):

I have a script that runs in the background, periodically doing some work and then sleeping for 30 seconds:

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

If I try to kill this script via kill or kill INT, it takes 30 seconds to respond to the signal.

I will answer this question below, since I found a good explanation online.

(My original, embarrassingly un-researched question)

This question is for a bash script that includes the following trap:

trap 'echo "Exiting...">&2; kill $childPID 2>/dev/null; exit 0' \
SIGALRM SIGHUP SIGINT SIGKILL SIGPIPE SIGPROF SIGTERM \
SIGUSR1 SIGUSR2 SIGVTALRM SIGSTKFLT

If I run the script in the foreground, and hit CTRL-C, it gets the signal immediately and exits (under one sec).

If I run the same script in the background (&), and kill it via kill or kill -INT, it takes 30 seconds before getting the signal.

Why is that, and how can I fix it?


回答1:


Possible reason: signals issued while a process is sleeping are not delivered until wake-up of the process. When started via the command line, the process doesn't sleep, so the signal gets delivered immediately.




回答2:


As explained in http://mywiki.wooledge.org/SignalTrap --

"When bash is executing an external command in the foreground, it does not handle any signals received until the foreground process terminates" - and since sleep is an external command, bash does not even see the signal until sleep finishes.

That page has a very good overview of signal processing in bash, and work-arounds to this issue. Briefly, one correct way of handling the situation is to send the signal to the process group instead of just the parent process:

kill -INT -123   # will kill the process group with the ID 123

Head over to the referenced page for a full explanation (no sense in my reproducing any more of it here).




回答3:


@RashaMatt, I was unable to get the read command to work as advertised on Greg's wiki. Sending a signal to the script simply did not interrupt the read. I needed to do this:

#!/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

...send the desired signal to the shell's pid displayed from the Shell $$ started line, and watch the excitement.

waiting on a sleep is simpler, true, but some os' don't have sleep infinity, and I wanted to see how Greg's read example would work (which it didn't).



来源:https://stackoverflow.com/questions/20513372/why-does-my-bash-script-take-so-long-to-respond-to-kill-when-it-runs-in-the-back

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!