Bash-Skript sieht SIGHUP nicht?

11

Ich habe das folgende Skript:

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

Wenn ich sende SIGHUP(mit kill -HUP pid), passiert nichts.

Wenn ich das Skript leicht ändere:

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

... dann macht das Skript das echo HUPDing richtig, wenn es beendet wird (wenn ich Strg + C drücke):

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

Was ist los? Wie soll ich ein Signal SIGHUPan dieses Skript senden (es muss nicht unbedingt sein )?

Roger Lipscombe
quelle
4
Das Signal wird geliefert und der Signalhandler wird ausgeführt, wenn der catProzess abgeschlossen ist. Probieren Sie Ihr ursprüngliches Skript aus und drücken Sie Ctrl+D, um den catVorgang zu beenden. Während der catProzess im Vordergrund steht, wird das HUPSignal nicht bearbeitet. Versuchen Sie es erneut mit catersetzt durch read(eine eingebaute Shell).
Kusalananda
Perfekt. Hat jemand Lust, daraus eine Antwort zu machen?
Roger Lipscombe
Ich weiß, dass es so funktioniert, aber ich werde jemanden, der mehr Einblick als ich hat, in das Warum und Warum die Antwort geben.
Kusalananda
Ich habe es while true; do read; doneam Ende verwendet, andernfalls wird es auch durch Eingabe von Text beendet, und ich möchte, dass es bei Strg + C beendet wird.
Roger Lipscombe

Antworten:

20

Das Bash-Handbuch besagt:

Wenn bash auf den Abschluss eines Befehls wartet und ein Signal empfängt, für das ein Trap gesetzt wurde, wird der Trap erst ausgeführt, wenn der Befehl abgeschlossen ist.

Das bedeutet, dass trotz des Empfangs des Signals bashbeim Senden Ihre Falle bei SIGHUP nur aufgerufen wird, wenn sie catendet.

Wenn dieses Verhalten unerwünscht ist, verwenden bashSie entweder integrierte Funktionen (z. B. read+ printfin einer Schleife anstelle von cat) oder Hintergrundjobs (siehe Stéphanes Antwort ).

xhienne
quelle
9

@xhienne hat bereits erklärt, warum , aber wenn Sie möchten , dass das Signal sofort aktiviert wird (und das Skript nicht beendet wird), können Sie Ihren Code ändern in:

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

Der kleine Tanz mit Dateideskriptoren besteht darin, die Tatsache zu bashumgehen , dass stdin /dev/nullfür im Hintergrund gestartete Befehle umgeleitet wird .

Stéphane Chazelas
quelle
Funktioniert dies, weil der Codeblock in einer Subshell ausgeführt wird?
Pysis