Le script bash ne voit pas SIGHUP?

11

J'ai le script suivant:

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

Lorsque j'envoie SIGHUP(utilise kill -HUP pid), rien ne se passe.

Si je change légèrement le script:

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

... alors le script fait ce echo HUPqu'il faut à sa sortie (lorsque j'appuie sur Ctrl + C):

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

Que se passe-t-il? Comment dois-je envoyer un signal (il ne doit pas nécessairement l'être SIGHUP) à ce script?

Roger Lipscombe
la source
4
Le signal sera délivré et le gestionnaire de signaux s'exécutera à la fin du catprocessus. Essayez votre script d'origine et appuyez sur Ctrl+Dpour catquitter le processus. Pendant que le catprocessus est au premier plan, le HUPsignal n'est pas mis à exécution . Essayez à nouveau avec catremplacé par read(un shell intégré).
Kusalananda
Parfait. Quelqu'un veut-il transformer cela en une réponse?
Roger Lipscombe
Je sais que cela fonctionne de cette façon, mais je laisserai quelqu'un qui a plus d'informations que moi sur le pourquoi et le comment faire la réponse.
Kusalananda
J'ai utilisé while true; do read; doneà la fin, sinon la saisie de texte le fait également se fermer, et je veux qu'il se ferme sur Ctrl + C.
Roger Lipscombe

Réponses:

21

Le manuel de Bash déclare:

Si bash attend la fin d'une commande et reçoit un signal pour lequel un trap a été défini, le trap ne sera pas exécuté tant que la commande ne sera pas terminée.

Cela signifie que malgré le signal reçu bashlorsque vous l'envoyez, votre piège sur SIGHUP ne sera appelé qu'à la catfin.

Si ce comportement n'est pas souhaitable, alors utilisez soit des commandes bashintégrées (par exemple read+ printfdans une boucle au lieu de cat), soit utilisez des tâches d'arrière-plan (voir la réponse de Stéphane ).

xhienne
la source
9

@xhienne a déjà expliqué pourquoi , mais si vous vouliez faire agir le signal immédiatement (et ne pas quitter le script), vous pouvez changer votre code en:

#! /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"

La petite danse avec les descripteurs de fichiers consiste à contourner le fait que bashredirige stdin vers les /dev/nullcommandes lancées en arrière-plan.

Stéphane Chazelas
la source
Est-ce que cela fonctionne parce que le bloc de code s'exécute dans un sous-shell?
Pysis