Jak zrobić ctrl + c / not / przerwać pętlę while?

11

Biorąc pod uwagę tę pętlę:

while sleep 10s ; do
  something-that-runs-forever
done

Kiedy naciskam Ctrl + C, cała pętla while zostaje przerwana. Chcę przerwać proces „coś”, odczekać 10 sekund, a następnie ponownie uruchomić „coś”.

Jak sprawić, by ctrl + c wpływał tylko na „coś”, a nie na pętlę while?

EDYCJA: „przerwij” jak w SIGINT. Zabić. Anulować. Zakończyć. Nie „przerywaj” jak w „pauzie”.

bos
źródło
Jeśli chcesz po prostu go zatrzymać, dlaczego nie użyć Ctrl + Z, poczekaj 10 sekund i uruchom fg? Po co w ogóle używać Ctrl + C?
terdon
@terdon: Dzięki za komentarz, być może wpadłem z odpowiedzią. Przeczytaj więcej na temat wymagań PO
Inian
@terdon: Nie chcę tego zatrzymywać. Chcę, żeby minęło 10 sekund, jak napisałem.
bos
Mówiłeś: What I want to do is to interrupt the "something"-process, let 10 seconds pass, and then restart "something". Jeśli naciśniesz Ctrl + Z, odczekaj 10 sekund, a następnie uruchom fg, dokładnie tak się stanie. Może mógłbyś edytować swoje pytanie i podać konkretny przykład, abyśmy mogli lepiej zrozumieć?
terdon
3
Myślałem, że w kontekście Ctrl + C przerwanie było jednoznaczne, ale oczywiście się myliłem. Teraz edytowałem.
bos

Odpowiedzi:

18

Powinno to działać, jeśli po prostu trap SIGINTdo czegoś. Like :( true).

#!/bin/sh
trap ":" INT    
while sleep 10s ; do
    something-that-runs-forever
done

Przerwanie something...nie powoduje teraz wyjścia powłoki, ponieważ ignoruje sygnał. Jednak jeśli ^ C sleepproces, zakończy się niepowodzeniem, a pętla zatrzymuje się z tego powodu. Przesuń sleepdo wnętrza pętli lub dodaj coś takiego, || trueaby temu zapobiec.

Zauważ, że jeśli użyjesz trap "" INTdo całkowitego zignorowania sygnału (zamiast przypisania do niego polecenia), zostanie on również zignorowany w procesie potomnym, więc też nie możesz przerwać something.... Jest to wyraźnie wspomniane w przynajmniej podręczniku Basha :

Jeśli arg jest łańcuchem pustym, wówczas sygnał określony przez każdy sigspec jest ignorowany przez powłokę i wywoływane przez nią polecenia. [...] Sygnały zignorowane przy wejściu do powłoki nie mogą zostać uwięzione ani zresetowane.

ilkkachu
źródło
Czy można to osiągnąć również w obecnej powłoce? (Nie w skrypcie.)
1
Możesz do (trap - INT; something-that-runs-forever)zezwolić na przerwanie polecenia. Ponadto, nie ma potrzeby uruchamiania :- można po prostu użyć pusty ciąg zignorować sygnał: trap '' INT. Wszystko to jest POSIX i powinno działać na dowolnej zgodnej powłoce (nie tylko Bash).
Toby Speight
Należy również zauważyć, że pisanie SIGINTw całości nie jest ściśle przenośny: „ Wdrożenia mogą zezwolić nazwy z SIGprzedrostkiem lub zignorować sprawę nazw sygnałów jak przedłużenie . (Podkreślenie moje)”
Toby Speight
możesz przekazać pusty ciąg znaków jako akcję, aby zignorować sygnał, np. trap "" INT(także posix)
daf
@TobySpeight, powodem, dla którego użyłem trap :zamiast tego trap ""było właśnie to, że nie zignorowałem sygnału (ale zamiast tego uczyniłem go brakiem operacji ), abyśmy nie musieli robić nic innego, aby móc przerwać główny somethingprogram.
ilkkachu
0

Inną opcją jest something-that-runs-foreverobsługa sygnału (wychodzenie z gracją po odebraniu). Oczywiście ma sens tylko wtedy, gdy ten program jest używany w wielu skryptach, a pożądane zachowanie na CTRL+ Cjest systematycznie takie samo - aby kontynuować wykonywanie skryptu.

Dmitrij Grigoriew
źródło
ITYM „spać i ponownie wykonać się”, a nie „wyjść z gracją”?
Toby Speight