¿Por qué bash ignora SIGTERM?

10

A veces, cuando quiero cerrar sesión rápidamente, lo hago kill -15 -1. He notado que bash está ignorando a SIGTERM.

Me pregunto cuál es la razón de tal comportamiento bash .

No es muy UNIX ignorar SIGTERM sin una buena razón, ¿no?

ACTUALIZAR:

mismo (no) efecto para todos:

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

ACTUALIZACIÓN2:

De man bash :

Cuando bash es interactivo, en ausencia de trampas, ignora SIGTERM

Entonces se hace a propósito. ¿Pero por qué?

Michał Šrajer
fuente
¿Qué asesinato estás usando? /bin/killo la cáscara incorporada? Si es lo último, supongo que el caparazón no se suicidará con su propio incorporado.
terdon
@terdon: Utilicé builtin, pero no creo que esa sea la razón para no suicidarse.
Michał Šrajer
1
Si desea cerrar sesión rápidamente, use Ctrl + d
YoMismo
1
@YoMismo: "cerrar sesión de la sesión X"
Michał Šrajer
2
@ MichałŠrajer: Ctrl-Alt-Retroceso hace esto por mí en Xorg ... aunque quizás tengas que habilitarlo en xorg.conf.
Laszlo Valko

Respuestas:

10

Primero, esto no es específico de bash. ATT ksh, dash y zsh se comportan de la misma manera: ignoran SIGTERM y SIGQUIT durante la edición de la línea de comandos; En cuanto a mksh, tampoco se cierra pero los trata como SIGINT.

Tanto el manual de ksh como el manual de bash justifican ignorar SIGTERM en estos términos:

para que eso kill 0no mate a un shell interactivo

kill 0mata todos los procesos en el grupo de procesos en el que está el shell¹. En pocas palabras, el grupo de procesos consta de todos los procesos que se ejecutan en primer plano en un terminal, o todos los procesos en segundo plano o trabajo suspendido.

Más precisamente, esto es lo que sucede en los depósitos modernos con control de trabajo . En tales shells, kill 0no sería útil, ya que el shell estaría en un grupo de proceso propio. Los shells más antiguos (o los shells modernos posteriores set +m) no crearon grupos de procesos para los comandos de fondo. Por lo tanto, puede usar el comando kill 0para eliminar todos los comandos en segundo plano sin cerrar la sesión. Por lo tanto, la kill 0lógica parece una vieja que ya no se justifica hoy en día, pero se mantiene por compatibilidad con versiones anteriores.

Sin embargo, hay otras situaciones similares en las que es útil hacer que la cáscara sea inmune. Considere el caso en el que tiene procesos que acaparan una terminal y desea matarlos sin cerrar sesión. Muchos sistemas tienen una herramienta como la pkillque le permite eliminar los procesos que se ejecutan en un terminal. Puede ejecutar pkill -t $TTYo pkill -QUIT -t $TTYeliminar todos los procesos que se ejecutan en el terminal actual, excepto el shell que ignora la señal.

Un shell normalmente desaparece cuando el usuario sale (con un comando como exito logout), o cuando su terminal señala el final de la entrada (el usuario puede causar esto presionando Ctrl+ D) o desaparece por completo. En este último caso, el shell recibe la señal SIGHUP, y no ignora esa.

Para su caso de uso de cerrar sesión en una sesión X, kill -15 -1lo hará, ya que mata el emulador de terminal que hace que el shell reciba SIGHUP. De hecho, es suficiente para matar el servidor X, pero eso requiere encontrar su ID de proceso. Si desea que el mismo comando funcione en una sesión de texto, puede usarlo kill -15 -1; exit. Es un comando bastante peligroso tener a tu alcance de todos modos.

¹ Esto no parece ser mencionado en los manuales de shell como una regla; Es una característica de la llamada al sistema subyacente. Se menciona explícitamente en la especificación POSIX .
² Hoy en día, para hacer eso, ejecute jobs -lpara ver una lista de trabajos con su ID de grupo de proceso y luego kill -123 -456 …elimine los grupos de proceso.

Gilles 'SO- deja de ser malvado'
fuente
5

Esto podría responder a su pregunta:

Cuando Bash es interactivo, en ausencia de trampas, ignora SIGTERM (para que 'kill 0' no elimine un shell interactivo), y SIGINT es capturado y manejado (para que la espera incorporada sea interrumpible). Cuando Bash recibe un SIGINT, se escapa de cualquier bucle en ejecución. En todos los casos, Bash ignora SIGQUIT. Si el control de trabajo está vigente (ver Control de trabajo), Bash ignora SIGTTIN, SIGTTOU y SIGTSTP.

Los comandos no incorporados iniciados por Bash tienen manejadores de señal establecidos en los valores heredados por el shell de su padre. Cuando el control de trabajo no está en vigor, los comandos asincrónicos ignoran SIGINT y SIGQUIT además de estos controladores heredados. Los comandos ejecutados como resultado de la sustitución de comandos ignoran las señales de control de trabajo generadas por teclado SIGTTIN, SIGTTOU y SIGTSTP.

El shell sale por defecto al recibir un SIGHUP. Antes de salir, un shell interactivo reenvía el SIGHUP a todos los trabajos, en ejecución o detenidos. Los trabajos detenidos se envían SIGCONT para garantizar que reciban el SIGHUP. Para evitar que el shell envíe la señal SIGHUP a un trabajo en particular, debe eliminarse de la tabla de trabajos con el código interno Desconocido (consulte el Código de control del trabajo) o marcarlo para que no reciba el mensaje SIGHUP usando disown -h.

Si la opción de shell huponexit se ha configurado con shopt (consulte The Shopt Builtin), Bash envía un SIGHUP a todos los trabajos cuando sale de un shell de inicio de sesión interactivo.

Si Bash está esperando que se complete un comando y recibe una señal para la cual se ha establecido una trampa, la trampa no se ejecutará hasta que se complete el comando. Cuando Bash está esperando un comando asincrónico a través del sistema de espera incorporado, la recepción de una señal para la cual se ha establecido una trampa hará que el sistema de espera regrese inmediatamente con un estado de salida superior a 128, inmediatamente después de lo cual se ejecuta la trampa.

FUENTE : El manual de GNU Bash

Petr
fuente
Cité esto en mi actualización2. El hombre afirma que bash lo está haciendo, pero no explica por qué tal decisión. La pregunta sigue siendo: ¿por qué?
Michał Šrajer