Почему Bash игнорирует SIGTERM?

10

Иногда, когда я хочу быстро выйти из системы, я делаю это kill -15 -1. Я заметил, что bash игнорирует SIGTERM.

Интересно, в чем причина такого поведения bash ?

Не слишком UNIX'ы игнорировать SIGTERM без веской причины, не так ли?

ОБНОВИТЬ:

одинаковый (нет) эффект для всех:

$ kill -TERM $$
$ type kill
kill is a shell builtin
$ command kill -TERM $$
$ /bin/kill -TERM $$

UPDATE2:

От человека Баш :

Когда bash интерактивен, при отсутствии ловушек он игнорирует SIGTERM

Так сделано специально. Но почему?

Михал Шрайер
источник
Какое убийство вы используете? /bin/killили оболочка встроенная? Если последнее, я предполагаю, что оболочка не убьет себя с помощью собственной встроенной функции.
Тердон
@terdon: Я использовал встроенный, но я не думаю, что это причина, чтобы не убивать его самостоятельно.
Михал Шрайер
1
Если вы хотите быстро выйти из системы, используйте Ctrl + d
YoMismo
1
@YoMismo: «Выйти из X сессии»
Михал Шрайер
2
@ MichałŠrajer: Ctrl-Alt-Backspace делает это для меня в Xorg ... хотя вам может потребоваться включить его в xorg.conf.
Ласло Валко

Ответы:

10

Во-первых, это не относится к Bash. ATT ksh, dash и zsh ведут себя одинаково: они игнорируют SIGTERM и SIGQUIT во время редактирования командной строки; что касается mksh, то он также не завершается, а обрабатывает их как SIGINT.

И руководство ksh, и руководство bash оправдывают игнорирование SIGTERM в следующих терминах:

так что kill 0не убивает интерактивную оболочку

kill 0убивает все процессы в группе процессов , в которой находится оболочка¹. В двух словах, группа процессов состоит из всех процессов, выполняющихся на переднем плане в терминале, или всех процессов в фоновом или приостановленном задании.

Точнее, это то, что происходит в современных оболочках с контролем работы . В таких оболочках kill 0это было бы бесполезно, поскольку оболочка находилась бы в отдельной группе процессов. Старые оболочки (или современные оболочки после set +m) не создавали групп процессов для фоновых команд. Таким образом, вы можете использовать команду, kill 0чтобы убить все фоновые команды, не выходя из системы. Таким образом, kill 0обоснование выглядит как старое, которое в настоящее время более не оправдано, но сохранено для обратной совместимости.

Однако есть и другие подобные ситуации, в которых полезно сделать оболочку иммунной. Рассмотрим случай, когда у вас есть процессы, блокирующие терминал, и вы хотите уничтожить их, не выходя из системы. Во многих системах есть такой инструмент, pkillкоторый позволяет вам убивать процессы, запущенные на терминале. Вы можете запустить pkill -t $TTYили pkill -QUIT -t $TTYубить все процессы, запущенные на текущем терминале, кроме оболочки, которая игнорирует сигнал.

Оболочка обычно уходит либо когда пользователь выходит из нее (с помощью команды exitили logout), либо когда ее терминал сигнализирует об окончании ввода (пользователь может вызвать это нажатием Ctrl+ D), либо вообще уходит. В этом последнем случае оболочка получает сигнал SIGHUP и не игнорирует его.

Для вашего случая выхода из сеанса X это kill -15 -1будет сделано, так как это убивает эмулятор терминала, в результате чего оболочка получает SIGHUP. На самом деле этого достаточно, чтобы убить X-сервер, но для этого необходимо найти его идентификатор процесса. Если вы хотите, чтобы та же команда работала в текстовом сеансе, вы можете использовать kill -15 -1; exit. В любом случае, это очень опасная команда.

Seem Это, как правило, не упоминается в руководствах по оболочке; это особенность основного системного вызова. Это явно упоминается в спецификации POSIX .
² В настоящее время для этого запустите, jobs -lчтобы увидеть список заданий с идентификатором их группы процессов, а затем kill -123 -456 …убить группы процессов.

Жиль "ТАК - прекрати быть злым"
источник
5

Это может ответить на ваш вопрос:

Когда Bash является интерактивным, при отсутствии каких-либо ловушек он игнорирует SIGTERM (так что «kill 0» не уничтожает интерактивную оболочку), а SIGINT перехватывается и обрабатывается (так, чтобы встроенная функция ожидания была прерываемой). Когда Bash получает SIGINT, он прерывает выполнение любых циклов. Во всех случаях Bash игнорирует SIGQUIT. Если контроль заданий действует (см. Контроль заданий), Bash игнорирует SIGTTIN, SIGTTOU и SIGTSTP.

Для не встроенных команд, запущенных Bash, в обработчиках сигналов установлены значения, унаследованные оболочкой от ее родителя. Когда управление заданиями не действует, асинхронные команды игнорируют SIGINT и SIGQUIT в дополнение к этим унаследованным обработчикам. Команды, выполняемые в результате подстановки команд, игнорируют генерируемые клавиатурой сигналы управления заданиями SIGTTIN, SIGTTOU и SIGTSTP.

Оболочка выходит по умолчанию при получении SIGHUP. Перед выходом интерактивная оболочка отправляет SIGHUP всем работам, запущенным или остановленным. Остановленные задания отправляются SIGCONT, чтобы гарантировать получение SIGHUP. Чтобы предотвратить отправку оболочкой сигнала SIGHUP на конкретное задание, его следует удалить из таблицы заданий с помощью встроенной функции disown (см. Раздел «Встроенные элементы управления заданиями») или пометить, чтобы она не получала SIGHUP с помощью disown -h.

Если параметр оболочки huponexit был установлен с помощью shopt (см. Построение магазина), Bash отправляет SIGHUP всем работам при выходе из интерактивной оболочки входа.

Если Bash ожидает завершения команды и получает сигнал, для которого установлена ​​ловушка, ловушка не будет выполнена, пока команда не завершится. Когда Bash ожидает асинхронную команду через встроенную функцию ожидания, прием сигнала, для которого установлена ​​ловушка, заставит встроенную функцию ожидания немедленно вернуться со статусом выхода больше 128, сразу после чего ловушка будет выполнена.

ИСТОЧНИК : Руководство GNU Bash

Petr
источник
Я процитировал это в моем обновлении2. Человек заявляет, что Баш делает это, но не объясняет, почему такое решение. Остается вопрос - почему?
Михал Шрайер