Выполните команду или функцию, когда SIGINT или SIGTERM отправляются самому родительскому сценарию, а не дочерним процессам

11

Допустим, у меня есть это script.sh

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

echo "Some other text"
#other commands here
sleep infinity

Я хочу script.shвыполнить функцию exit_scriptвсякий раз, когда она получает SIGINTили, SIGTERM например:

killall script.sh # it will send SIGTERM to my script

и я хочу, чтобы мой сценарий выполнил это

exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

Я пытался реализовать эту функцию с помощью trap

trap exit_script SIGINT SIGTERM

Человек, который ответил на мой вопрос, доказал, что я неправ.
но это не сработало, потому что, trapкажется, реагирует только на сигналы, посылаемые дочерним процессам. Будучи новичком, я не мог расшифровать trapсправочную страницу, поэтому, вероятно, пропустил решение.

Я полагаю, именно это и делают "настоящие" программы, такие как Chromium, когда вы их отправляете SIGTERM

С https://major.io/2010/03/18/sigterm-vs-sigkill/

Приложение может определить, что оно хочет сделать после получения SIGTERM. Хотя большинство приложений будут очищать свои ресурсы и останавливаться, некоторые могут этого не делать.

Bosa Djo
источник
2
обычно ругательства считаются неприемлемыми для почтительного разговора
кот
редактировать предложение одобрено хорошо, хорошо сделано, не весело я его получаю
bosa djo
это не значит, что веселье не допускается, просто это считается оскорбительным
кот
1
@cat Я подумал о твоих аргументах, и ты прав, извини за моё дурачество
bosa djo

Ответы:

15

trapсам реагирует на сигналы вызывающего процесса. Но вы должны позвонить до получения сигнала. Я имею в виду, в начале вашего сценария.

Кроме того, если вы хотите использовать функцию kill -- -$$, которая посылает сигнал также в ваш сценарий, вам нужно очистить ловушку перед выполнением kill, иначе вы закончите бесконечным циклом kill && trap .

Например:

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    trap - SIGINT SIGTERM # clear the trap
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

trap exit_script SIGINT SIGTERM

echo "Some other text"
#other commands here
sleep infinity

Как поясняется в комментариях, проблема заключается в том, что сценарий получает сигнал, но ожидает завершения спящей программы перед обработкой принятого сигнала. Таким образом, вы должны уничтожить дочерние процессы (в данном случае спящий процесс), чтобы запустить действие trap. Вы можете сделать это примерно так:

kill -- -$(pgrep script.sh)

Или как указано в комментариях:

killall -g script.sh
Zuazo
источник
1
Я, наверное, что-то упускаю, потому что это не работает, вот что я делаю. script.sh &; killall script.sh но ничего не делает.
bosa djo
Я выполняю скрипт .sh &; # тогда я делаю свое дело; killall script.sh и это не убивает script.sh
bosa djo
1
Проблема, вероятно, заключается в том, что скрипт получает сигнал, но ожидает завершения спящей программы перед обработкой. Попробуйте с помощью ./script.sh & sleep 1 && kill -- -$(pgrep script.sh)отправить сигнал уничтожения также дочерним процессам вашего скрипта.
zuazo
@zuazo Вы должны добавить эту интересную и важную информацию в свой ответ :)
кошка,
1
Здорово, боса дджо. Я добавил ваше альтернативное решение в ответ ;-)
zuazo