Как распространять сигнал через набор скриптов?
У меня есть набор скриптов, которые контролируются основным. Я хочу захватить сигнал ctrl + c в главном script и передать его другим. Другие скрипты также должны улавливать этот сигнал (из основного script) и выполнять некоторую очистку...
Я попытался отправить kill -s SIGINT
своим дочерним элементам, но они, похоже, не могут поймать сигнал (даже если trap 'Cleanup' SIGINT
определяется на дочерних скриптах)
Любые подсказки, как это реализовать?
Ответы
Ответ 1
В следующем примере демонстрируется родительский script, который что-то делает (sleep 5
) после запуска двух дочерних объектов, которые выполняют свою собственную работу (также sleep 5
). Когда родитель выйдет (по какой-либо причине), он сигнализирует, что дети заканчиваются (не SIGINT
, завершение сигнализируется SIGTERM
, также сигнал по умолчанию kill
). Затем дети делают свое дело на приеме SIGTERM
. Если дети сами по себе являются сценариями, я рекомендую вам переключить ловушку на TERM
в ловушку на EXIT
, чтобы дети очищались независимо от причины их окончания (до тех пор, пока она не будет доступна).
Обратите внимание на использование wait
. Bash не прерывает выполнение не встроенных команд при получении сигнала. Вместо этого он ждет их завершения и обработки сигнала после выполнения команды. Если вы используете wait
, Bash немедленно останавливается и сразу же обрабатывает сигнал.
#!/usr/bin/env bash
trap 'echo parent shutting down; kill $(jobs -p)' EXIT
{ trap 'echo child 1 signaled' TERM; sleep 5 & wait; } &
{ trap 'echo child 2 signaled' TERM; sleep 5 & wait; } &
sleep 5
Ответ 2
Вы пытались:
1) Настройте ловушки в каждом script (master/childs), где они вам нужны
2) Отправить мастеру убить с ним ПИД-код отрицается, чтобы убить всю группу процессов, я имею в виду:
kill -15 -$PID
убить человека | grep -C1 Отрицательный
Ответ 3
ГЛАВНЫЙ РОДИТЕЛЬ SCRIPT ГОЛОВА ПЕРЕД НАЧАЛО ГЛАВЫ:
#Catch control-c and clean up testd instances if necessary
cleanup () {
clear
echo "Caught Signal. Shutting Down MAIN."
if [ "$MAIN_on" -eq 1 ]
then
M_shutdown
fi
exit 1
}
В основной части script, когда вы создаете подпроцессы, вы поддерживаете массив с идентификаторами proc каждого из них. Чтобы загрузить PID в массив, установите значение для последнего порожденного процесса, например. поместите следующее после каждой икры суб-оболочки.
proc_id_array[1]=$!
Содержание M_shutdow будет чем-то вроде...
M_shutdown () {
if [ "$MAIN_on" -eq 1 ]
then
echo "Stopping Main"
echo "shutting down active subscripts"
count_proc_id=1
while [ "$count_proc_id" -lt "$max_proc_id" ]
do
kill ${proc_id_array[$count_proc_id]} > /dev/null 2>&1
DATE=$(date +%m%d%y-%k:%M)
echo "$DATE: ${proc_name_array[$count_proc_id]} \(PID: ${proc_id_array[$count_proc_id]}\) stopped." >> $logfile
proc_id_array[$count_proc_id]="A"
count_proc_id=`expr $count_proc_id + 1`
done
echo "MAIN stopped"
MAIN_on=0
sleep 5
else
echo "MAIN already stopped."
sleep 1
fi
}
Ответ 4
Я не уверен, что вы подразумеваете под "другими сценариями, которые должны улавливать этот сигнал из основного script"? Как подпроцесс script использует код в главном script для захвата сигнала?
Я не хочу пытаться писать много кода для вас, потому что я не знаю точно, что вы подразумеваете под "скриптами, управляемыми основным", но, предположительно, вы запускаете некоторые подпроцессы, тогда есть контрольный цикл, который проверяет если другие скрипты вышли и могут получить статус выхода? Если это так, то, что имеет для меня наибольшее значение, - это для каждого script сделать свое собственное удержание и очистку. Когда основной script ловушки передают сигнал, он может, если нужно, передать сигнал всем детям (через kill -s <signal> pid
). Когда дочерний процесс захватывает сигнал, он может вернуть статус выхода, указывающий, что он был прерван этим сигналом. Затем главный может обработать этот статус выхода - возможно, так же, как если бы он получил этот конкретный сигнал. (Функции оболочки - ваш друг.)