Co się dzieje, że zarówno bashi pingotrzyma SIGINT ( bashistota nie interaktywne, zarówno pingi bashdziałać w tej samej grupie procesów, które zostały utworzone i ustawione jako grupy procesów planie terminala przez interaktywnej powłoki uruchomiono ten skrypt z).
Jednak bashobsługuje SIGINT asynchronicznie, dopiero po zakończeniu aktualnie uruchomionej komendy. bashkończy działanie dopiero po otrzymaniu tego SIGINT, jeśli aktualnie uruchomione polecenie umiera z SIGINT (tzn. jego status wyjścia wskazuje, że został zabity przez SIGINT).
$ bash -c 'sh -c "trap exit\ 0 INT; sleep 10; :"; echo here'
^Chere
Powyżej bash, shi sleepotrzymać SIGINT po naciśnięciu Ctrl-C, ale shwychodzi zwykle z kodem 0 wyjścia, więc bashpomija SIGINT, dlatego widzimy „tutaj”.
ping, przynajmniej ten z iputils, zachowuje się tak. Po przerwaniu drukuje statystyki i wychodzi ze statusem wyjścia 0 lub 1 w zależności od tego, czy odpowiedzi na ping zostały wysłane. Tak więc, gdy naciśniesz Ctrl-C podczas pingdziałania, bashnotatki, które nacisnąłeś Ctrl-Cw jego procedurach obsługi SIGINT, ale ponieważ pingwychodzą normalnie, bashnie wychodzą.
Jeśli dodasz sleep 1w tej pętli i naciśniesz Ctrl-Cpodczas sleepdziałania, ponieważ sleepnie ma specjalnego modułu obsługi w SIGINT, umrze i zgłosi bash, że zmarł w wyniku SIGINT, i w takim przypadku bashzakończy działanie (faktycznie zabije się za pomocą SIGINT, tak że zgłosić przerwanie rodzicowi).
Co do tego, dlaczego bashtak się zachowuje, nie jestem pewien i zauważam, że zachowanie nie zawsze jest deterministyczne. Właśnie zadałem pytanie na bashliście mailingowej dla programistów ( aktualizacja : @Jilles podał teraz powód swojej odpowiedzi ).
Jedyną znalezioną przeze mnie powłoką, która zachowuje się podobnie, jest ksh93 (aktualizacja, o której wspomina @Jilles, podobnie jak FreeBSDsh ). Tam SIGINT wydaje się wyraźnie ignorowany. I ksh93kończy działanie, gdy polecenie jest zabijane przez SIGINT.
Otrzymujesz takie samo zachowanie jak bashpowyżej, ale także:
ksh -c 'sh -c "kill -INT \$\$"; echo test'
Nie wyświetla „testu”. Oznacza to, że kończy działanie (zabijając się tam za pomocą SIGINT), jeśli polecenie, na które czekał, umiera SIGINT, nawet jeśli samo nie otrzymało tego SIGINT.
Obejściem byłoby dodanie:
trap 'exit 130' INT
W górnej części skryptu, aby wymusić bashwyjście po otrzymaniu SIGINT (pamiętaj, że w każdym razie SIGINT nie będzie przetwarzany synchronicznie, tylko po zakończeniu aktualnie uruchomionej komendy).
Najlepiej byłoby, gdybyśmy chcieli zgłosić naszemu rodzicowi, że zmarliśmy z powodu SIGINT (aby bashna przykład w przypadku innego skryptu ten bashskrypt również został przerwany). Wykonanie an exit 130to nie to samo, co umieranie SIGINT (chociaż niektóre powłoki ustawią się $?na tę samą wartość w obu przypadkach), jednak często jest używane do zgłaszania śmierci przez SIGINT (w systemach, w których SIGINT to 2, co jest najbardziej).
Jednak dla bash, ksh93lub FreeBSD sh, że nie działa. Ten status wyjścia 130 nie jest uważany przez SIGINT za śmierć, a skrypt nadrzędny nie przerywałby tam.
Zatem prawdopodobnie lepszą alternatywą byłoby zabicie się SIGINT po otrzymaniu SIGINT:
trap '
trap - INT # restore default INT handler
kill -s INT "$$"
' INT
for f in *.txt; do vi "$f"; cp "$f" newdir; done. Jeśli użytkownik wpisze Ctrl + C podczas edycji jednego z plików,vipo prostu wyświetli komunikat. Wydaje się uzasadnione, że pętla powinna być kontynuowana po zakończeniu edycji pliku przez użytkownika. (I tak, wiem, że można powiedziećvi *.txt; cp *.txt newdir; po prostu przesyłamforpętlę jako przykład.)