Почему мой bash-скрипт так долго реагирует на kill, когда работает в фоновом режиме?
(Вопрос пересмотрен, теперь, когда я больше понимаю о том, что на самом деле происходит):
У меня есть скрипт, который работает в фоновом режиме, периодически выполняет некоторую работу, а затем спит в течение 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 секунд.Почему это так и как я могу это исправить?
3 ответа
Возможная причина: сигналы, выдаваемые во время спящего процесса, не доставляются до запуска процесса. При запуске через командную строку процесс не спит, поэтому сигнал доставляется немедленно.
Как объяснено в http://mywiki.wooledge.org/SignalTrap -
"Когда bash выполняет внешнюю команду на переднем плане, он не обрабатывает никаких сигналов, полученных до тех пор, пока процесс на переднем плане не завершится" - и так как sleep
это внешняя команда, bash даже не видит сигнал, пока не закончится сон.
Эта страница имеет очень хороший обзор обработки сигналов в bash и обходных путей к этой проблеме. Вкратце, один правильный способ справиться с ситуацией - отправить сигнал группе процессов, а не только родительскому процессу:
kill -INT -123 # will kill the process group with the ID 123
Перейдите на страницу, на которую ссылаются, для полного объяснения (нет смысла в моем воспроизведении этого здесь).
@RashaMatt, я не смог получить read
Команда работать как рекламируется в вики Грега. Отправка сигнала сценарию просто не прервала чтение. Мне нужно было сделать это:
#!/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
... отправить желаемый сигнал на pid оболочки, отображаемый с Shell $$ started
линии и смотреть волнение.
wait
правда, спать проще, но у некоторых нет sleep infinity
и я хотел посмотреть, как у Грега read
пример будет работать (что не получилось).