Skrypt Bash nie widzi SIGHUP?

11

Mam następujący skrypt:

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

Kiedy wysyłam SIGHUP(za pomocą kill -HUP pid) nic się nie dzieje.

Jeśli nieznacznie zmienię skrypt:

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

... wtedy skrypt robi to echo HUPdobrze, gdy wychodzi (kiedy naciskam Ctrl + C):

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

Co się dzieje? Jak mam wysłać sygnał (niekoniecznie musi być SIGHUP) do tego skryptu?

Roger Lipscombe
źródło
4
Sygnał zostanie dostarczony, a procedura obsługi sygnału zostanie wykonana po zakończeniu catprocesu. Wypróbuj oryginalny skrypt i naciśnij, Ctrl+Daby catzakończyć proces. Gdy catproces jest na pierwszym planie, HUPsygnał nie jest poddawany działaniu. Spróbuj ponownie z catzastąpionym przez read(wbudowana powłoka).
Kusalananda
Doskonały. Czy ktoś ma ochotę zamienić to w odpowiedź?
Roger Lipscombe
Wiem, że to działa w ten sposób, ale pozwolę komuś, kto ma lepszy wgląd ode mnie, w dlaczego i gdzie odpowiedzą.
Kusalananda
Użyłem while true; do read; donena końcu, w przeciwnym razie wpisanie tekstu spowoduje również zamknięcie i chcę, aby zostało zamknięte na Ctrl + C.
Roger Lipscombe

Odpowiedzi:

21

Podręcznik Bash stwierdza:

Jeśli bash czeka na zakończenie komendy i odbiera sygnał, dla którego ustawiono pułapkę, pułapka nie zostanie wykonana, dopóki polecenie się nie zakończy.

Oznacza to, że pomimo odebrania sygnału bashpo jego wysłaniu pułapka na SIGHUP zostanie wywołana dopiero po catzakończeniu.

Jeśli takie zachowanie jest niepożądane, użyj bashwbudowanych funkcji (np. read+ printfW pętli zamiast cat) lub użyj zadań w tle (patrz odpowiedź Stéphane'a ).

Xhienne
źródło
9

@xhienne wyjaśnił już, dlaczego , ale jeśli chcesz, aby sygnał zadziałał od razu (i nie wychodził ze skryptu), możesz zmienić kod na:

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

Mały taniec z deskryptorami plików polega na obejściu tego, że bashprzekierowuje standardowe wejście /dev/nullna polecenia uruchamiane w tle.

Stéphane Chazelas
źródło
Czy to działa, ponieważ blok kodu działa w podpowłoce?
Pysis