У меня есть набор сценариев, которыми управляет основной. Я хочу захватить сигнал ctrl+c в основном сценарии и распространить его другим. Другие сценарии должны захватить этот сигнал также (из основного сценария) и сделать некоторую очистку...
Я попытался отправить kill -s SIGINT
детям, но они кажутся, что не могут поймать сигнал (даже если trap 'Cleanup' SIGINT
будучи определенным на дочерних сценариях)
Какие-либо подсказки, как понять это?
Я не уверен, что вы имеете в виду, говоря «другие сценарии должны перехватывать этот сигнал от основного сценария»? Как сценарий подпроцесса может использовать код в основном сценарии для перехвата сигнала?
Я не хочу пытаться написать для вас много кода, потому что я не знаю точно, что вы имеете в виду под «сценариями, управляемыми основным сценарием». "либо, но, предположительно, вы запускаете некоторые подпроцессы, а затем имеете цикл управления, который проверяет, завершились ли другие сценарии, и может получить их статус выхода? Если это так, то для меня важнее всего, чтобы каждый скрипт выполнял свой собственный захват и очистку. Когда основной сценарий перехватывает сигнал, он может при желании передать сигнал всем потомкам (через kill -s
). Когда дочерний процесс перехватывает сигнал, он может вернуть статус выхода, указывающий, что он был завершен этим сигналом. Затем основной модуль может обрабатывать этот статус выхода соответствующим образом - возможно, таким же образом, как если бы он сам получил этот конкретный сигнал. (Функции оболочки - ваш друг.)
Следующий пример демонстрирует родительский скрипт, который что-то делает (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
ГЛАВНЫЙ ЗАГОЛОВОК РОДИТЕЛЬСКОГО СКРИПТА ПЕРЕД ГЛАВНЫМ ЦИКЛОМ :::
#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
}
В основной части скрипта, когда вы порождаете подпроцессы, вы поддерживаете массив с идентификаторами процессов каждого из них. Чтобы загрузить 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
}