¿El script de Bash no ve SIGHUP?

11

Tengo el siguiente script:

#!/bin/bash
echo "We are $$"
trap "echo HUP" SIGHUP
cat    # wait indefinitely

Cuando envío SIGHUP(usando kill -HUP pid), no pasa nada.

Si cambio ligeramente el script:

#!/bin/bash
echo "We are $$"
trap "kill -- -$BASHPID" EXIT    # add this
trap "echo HUP" SIGHUP
cat    # wait indefinitely

... entonces el script hace echo HUPlo correcto al salir (cuando presiono Ctrl + C):

roger@roger-pc:~ $ ./hupper.sh 
We are 6233
^CHUP

¿Que esta pasando? ¿Cómo debo enviar una señal (no necesariamente tiene que ser SIGHUP) a este script?

Roger Lipscombe
fuente
44
La señal se entregará y el controlador de señal se ejecutará cuando catfinalice el proceso. Pruebe su secuencia de comandos original y presione Ctrl+Dpara que catsalga el proceso. Mientras el catproceso está en primer plano, HUPno se actúa sobre la señal. Intente nuevamente con catreemplazado por read(un shell incorporado).
Kusalananda
Perfecto. ¿Alguien quiere convertir eso en una respuesta?
Roger Lipscombe
Sé que funciona de esa manera, pero dejaré que alguien que tenga más información que yo sepa por qué y por qué responden.
Kusalananda
Lo utilicé while true; do read; doneal final, de lo contrario, ingresar texto hace que se cierre también, y quiero que se cierre en Ctrl + C.
Roger Lipscombe

Respuestas:

21

El manual de Bash dice:

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.

Eso significa que a pesar de que la señal se recibe bashcuando la envía, su trampa en SIGHUP solo se llamará cuando catfinalice.

Si este comportamiento no es deseable, use bashbuiltins (por ejemplo, read+ printfen un bucle en lugar de cat) o use trabajos en segundo plano (consulte la respuesta de Stéphane ).

xhienne
fuente
9

@xhienne ya ha explicado por qué , pero si desea que la señal actúe de inmediato (y no salir del script), puede cambiar su código a:

#! /bin/bash -
interrupted=true
trap 'interrupted=true; echo HUP' HUP

{ cat <&3 3<&- & pid=$!; } 3<&0

while
  wait "$pid"
  ret=$?
  "$interrupted"
do
  interrupted=false
done
exit "$ret"

El pequeño baile con los descriptores de archivo es evitar el hecho de que bashredirige stdin a los /dev/nullcomandos iniciados en segundo plano.

Stéphane Chazelas
fuente
¿Funciona esto porque el bloque de código se ejecuta en una subshell?
Pysis