Jeśli używam trap
jak opisano np. Na http://linuxcommand.org/wss0160.php#trap, aby złapać ctrl-c (lub podobny) i oczyścić przed wyjściem, zmieniam zwrócony kod wyjścia.
Teraz prawdopodobnie nie będzie to miało znaczenia w świecie rzeczywistym (np. Ponieważ kody wyjścia nie są przenośne, a ponadto nie zawsze są jednoznaczne, jak omówiono w Domyślnym kodzie wyjścia po zakończeniu procesu? ), Ale wciąż zastanawiam się, czy istnieje naprawdę nie ma sposobu, aby temu zapobiec i zamiast tego zwrócić domyślny kod błędu dla przerwanych skryptów?
Przykład (w bash, ale moje pytanie nie powinno być uważane za specyficzne dla bash):
#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _
Wynik:
$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT
EXIT
$ echo $?
1
(Edytowane, aby usunąć, aby było bardziej zgodne z POSIX).
(Ponownie edytowane, aby uczynić go skryptem bash, moje pytanie nie jest jednak specyficzne dla powłoki).
Zmodyfikowano, aby używać przenośnego „INT” jako pułapki na rzecz nieprzenośnego „SIGINT”.
Edytowane, aby usunąć bezużyteczne nawiasy klamrowe i dodać potencjalne rozwiązanie.
Aktualizacja:
Rozwiązałem to teraz, po prostu wychodząc z kodami błędów na stałe i zatrzymując EXIT. Może to być problematyczne w niektórych systemach, ponieważ kod błędu może się różnić lub pułapka EXIT nie jest możliwa, ale w moim przypadku jest wystarczająca.
trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
read
czytać z bieżącego koprocesu itrap cmd SIGINT
nie będzie działał, ponieważ standard mówi, że powinieneś używaćtrap cmd INT
.read -p
czyta dane wejściowe z bieżącego koprocesu.Odpowiedzi:
Wszystko, co musisz zrobić, to zmienić moduł obsługi EXIT wewnątrz modułu procedury czyszczenia. Oto przykład:
źródło
trap cleanup INT
zamiasttrap cleanup EXIT
?W rzeczywistości, przerywanie wewnętrznego bashu
read
wydaje się nieco inne niż przerywanie polecenia uruchamianego przez bash. Normalnie, kiedy wchodzitrap
,$?
jest ustawiony i można go i wyjść z tej samej wartości zachowania:Jeśli skrypt zostanie przerwany podczas wykonywania polecenia podobnego
sleep
lub nawet wbudowanegowait
, zobaczysza kod wyjścia to 130. Jednak
read -p
wydaje się, że$?
ma wartość 0 (i tak w mojej wersji bash 4.3.42).Obsługa sygnałów podczas
read
może być w toku, zgodnie z plikiem zmian w mojej wersji ... (/ usr / share / doc / bash / CHANGES)źródło
read
, jak zauważono w pliku CHANGES (dodanym do mojej odpowiedzi). Może to być praca w toku.128 + signo
jako kodu wyjścia sygnałów, używa ksh93256 + signo
. POSIX mówi: coś powyżej 128 ....Każdy zwykły kod wyjścia sygnału będzie dostępny
$?
po wejściu do obsługi pułapki:Jeśli istnieje osobna pułapka WYJŚCIA, możesz zastosować tę samą metodologię: natychmiast zachowaj status wyjścia przekazywany z procedury obsługi sygnału (jeśli istnieje) czyszczenie, a następnie zwróć zapisany status wyjścia.
źródło
local
nie jest POSIX.{ba,z}sh
. AFAIK, to najlepsze, co można zrobić, niezależnie od tego.$?
jest 1 niezależnie od odbieranego sygnału).Zwrócenie tylko kodu błędu nie wystarcza, aby zasymulować wyjście przez SIGINT. Dziwi mnie, że do tej pory nikt o tym nie wspominał. Dalsza lektura: https://www.cons.org/cracauer/sigint.html
Właściwy sposób to:
Działa to z Bash, Dash i zsh. Aby zwiększyć przenośność, musisz użyć specyfikacji sygnału numerycznego (z drugiej strony, zsh oczekuje parametru ciągu dla
kill
polecenia ...)Zwróć także uwagę na specjalne traktowanie
EXIT
sygnału. Wynika to z tego, że niektóre powłoki (mianowicie Bash) również wykonują pułapkiEXIT
dla dowolnego sygnału (po ewentualnie zdefiniowanych pułapkach na tym sygnale). ZresetowanieEXIT
pułapki zapobiega temu.Wykonywanie kodu tylko przy „normalnym” wyjściu
Sprawdzenie
[ $sig = EXIT ]
pozwala na wykonanie kodu tylko przy normalnym (nie sygnalizowanym) wyjściu. Jednak wszystkie sygnały muszą mieć pułapki, które w końcu resetują pułapkęEXIT
;normal_exit_only_cleanup
będą również wzywane do sygnałów, które tego nie robią. Zostanie również wykonane przez wyjście przezset -e
. Można to naprawić poprzez zalewkowanieERR
(które nie jest obsługiwane przez Dash) i dodanie zaznaczenia[ $sig = ERR ]
przedkill
.Uproszczona wersja tylko Bash
Z drugiej strony takie zachowanie oznacza, że w Bash możesz po prostu to zrobić
po prostu wykonać kod czyszczenia i zachować status wyjścia.
edytowane
Opracuj zachowanie Basha: „WYJŚCIE łapie wszystko w pułapkę”
Usuń sygnał KILL, który nie może zostać uwięziony
Usuń prefiksy SIG z nazw sygnałów
Nie próbuj
kill -s EXIT
Weź
set -e
pod uwagę / ERRźródło
SIGINT
jest sposobem na jego zamknięcie i może zdecydować o wyjściu z 0, jeśli udało mu się zakończyć bez błędu lub innym kodem błędu, jeśli nie zamknął się czysto. Sprawa w punkcie:top
. Uruchom,top; echo $?
a następnie naciśnij Ctrl-C. Status zrzucony na ekran będzie wynosił 0.