Я пытаюсь настроить сценарий оболочки так, чтобы он запускал фоновые процессы, и когда я нажимаю Ctrl + C сценарий оболочки, он убивает детей, а затем завершает работу.
Лучшее, что мне удалось придумать, это вот это. Кажется, что kill 0 -INT
также убивает сценарий до того, как произойдет ожидание, поэтому сценарий оболочки умирает до завершения дочерних процессов.
Есть идеи, как заставить этот сценарий оболочки ждать, пока дети умрут после отправки INT?
#!/bin/bash
trap 'killall' INT
killall() {
echo **** Shutting down... ****
kill 0 -INT
wait # Why doesn't this wait??
echo DONE
}
process1 &
process2 &
process3 &
cat # wait forever
Во-первых, вы должны знать, что kill 0
отправить сигнал всем процессам в текущей группе процессов. (видеть kill (1) - справочная страница Linux) Полагаю, что убивает больше, чем следовало бы. Вот почему wait
не ждет, он по какой-то причине прекращается. Лучше всего для решения этой проблемы перебрать выполняемые задания из jobs -pr
убийство по одному: таким образом я гарантирую, что в этот момент сигнал будет отправлен только дочерним процессам и ничего более.
Чтобы заставить это работать, я провел несколько тестов, но застрял на отправке SIGINT дочерним процессам. Они просто на это не реагируют! Поискав в Интернете, я нашел этот ответ на Stack Overflow:
https://stackoverflow.com/questions/2524937/how-to-send-a-signal-sigint-from-script-to-script-bash
Итак, настоящая проблема в том, что вы не можете отправить SIGINT из одного скрипта в другой, потому что в неинтерактивных оболочках сигнал игнорируется. Мне не удалось обойти эту проблему (используя bash -i
вызвать дочерний скрипт не получится).
Я знаю, что вы, вероятно, захотите отправить SIGINT и подождать, пока дочерние процессы корректно завершатся, но если вы не против использовать SIGTERM (или любой другой сигнал, кроме SIGINT), это лучший сценарий, который я написал:
#!/bin/bash
trap 'killall' INT
killall() {
echo '**** Shutting down... ****'
jobs -pr
for i in $(jobs -pr); do
kill -TERM $i
done
wait
echo DONE
}
./long.sh &
./long.sh &
./long.sh &
cat # wait forever
Для проверки я создал это long.sh
сценарий:
#!/bin/bash
trap 'killall' TERM
echo "Started... $$" >> file.txt
killall() {
# shutting down gracefully
echo "Finished... $$" >> file.txt
exit # don't forget this!
}
# infinite loop
while true; do echo loop >/dev/null ; done
В последнем скрипте я не использовал sleep
функция, потому что она создает новый процесс, который остается в памяти даже после завершения сценария. В вашем сценарии вы можете вызывать новые процессы, но вы должны обеспечить широковещательную передачу SIGTERM (или любого другого сигнала, который вы использовали) всем из них.
Кажется, это работает. Обязательно используйте "/ usr / bin / kill", а не встроенное в Bash "kill".
[myles@marklar ~]$ /usr/bin/kill --version
kill from util-linux-2.13-pre7
Обратите внимание, что управление заданиями не включено в неинтерактивных оболочках Bash (например, скриптах).
#!/bin/bash
trap kill_jobs 2
kill_jobs()
{
while /usr/bin/kill 0; do :; done
exit 0
}
foo &
foo &
foo &
sleep 777777