Co się dzieje
Po naciśnięciu Ctrl+ CThe SIGINT
sygnał dostarczany jest do całej grupy procesów planie . Tutaj jest wysyłany zarówno do find
procesu, jak i do procesu powłoki wywołującej. find
reaguje natychmiastowym wyjściem, a powłoka reaguje na wywołanie pułapki.
Jeśli kod w pułapce zostanie zwrócony (tzn. Nie wywołuje exit
), wykonanie następuje po poleceniu, które zostało przerwane przez sygnał. Tutaj po find
komendzie następuje koniec skryptu, więc skrypt i tak natychmiast się kończy. Ale możesz zobaczyć różnicę między wprowadzeniem 0 i 1, dodając kolejne polecenie:
find /
echo "find returned $?"
Sposób na robienie tego, co chcesz (ale prawdopodobnie nie powinieneś)
Możesz robić co chcesz; ale ta część mojej odpowiedzi dotyczy bardziej odkrywania programowania powłoki niż rozwiązywania rzeczywistego problemu.
- Ze względów projektowych sygnał, który można zrestartować, nie jest tym, czego normalnie można oczekiwać w przypadku stosunkowo prostych programów, którymi zwykle są skrypty powłoki. Oczekuje się, że Ctrl+ Czabije skrypt.
- Jak zobaczysz poniżej, i tak rozszerza możliwości powłoki.
Jeśli chcesz uniknąć zabijania find
, trzeba go uruchomić w tle : find / &
. Następnie użyj wait
wbudowanego programu, aby poczekać, aż zakończy się normalnie. Sygnał przerwie wait
wbudowane, które można uruchomić w pętli, dopóki nie otrzymasz sygnału, który chcesz propagować. Następnie użyj, kill
aby zabić pracę.
hell () {
echo "Do you want to quit? Press 1 for yes and 0 for no"
read n
if [ "$n" = 1 ]; then
# Kill the job if it's running, then exit
if [ -n "$job_pid" ]; then kill $job_pid; fi
exit 1
fi
}
job_pid=
trap "hell" SIGINT
# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
echo "resuming wait"
done
job_pid=
echo last exit code: $?
Istnieją ograniczenia tego podejścia w powłoce:
- Jest warunek wyścigu: jeśli naciśniesz Ctrl+ Ctuż po zakończeniu zadania, ale przed
job_pid=
linią, program obsługi sygnału spróbuje zabić $jobpid
, ale proces już nie istnieje (nawet jako zombie, ponieważ wait
już go wykorzystał), a proces Identyfikator mógł zostać ponownie wykorzystany w innym procesie. Nie jest to łatwe do naprawienia w powłoce (może przez ustawienie modułu obsługi dla SIGCHLD
?).
- Jeśli potrzebujesz statusu zwrotu z pracy, musisz skorzystać z
wait $job_pid
formularza. Ale wtedy nie można odróżnić „ wait
został przerwany przez sygnał” od „zadania zostało zabite przez sygnał” (ani od „zadania zakończonego z własnej woli ze statusem zwrotu ≥128”, ale jest to ogólny fakt w skorupie programowanie).
- Nie rozszerzy się to łatwo, jeśli w ogóle, na wiele podwiązek. Zauważ, że zachowanie pułapek i sygnałów jest często zaskakujące, gdy wykraczasz poza podstawy w większości implementacji powłoki (tylko ksh robi to dobrze).
Aby pokonać te ograniczenia, użyj bardziej wyszukanego języka, takiego jak Perl lub Python.