Bash Loop - Jak zatrzymać pętlę po naciśnięciu Control-C wewnątrz polecenia?

35

Synchronizuję kilka katalogów. Mam otwarty terminal bash i wykonuję coś takiego:

for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; done

Jeśli jednak chcę zatrzymać wszystko, naciskam Control-C. To zatrzymuje rsync, ale potem przechodzi do następnego. W tym przypadku zdaję sobie sprawę z tego, co się wydarzyło, a następnie po prostu naciskaj klawisz Control-C jak szaleniec, aż wszystko znów zadziała.

Czy jest jakiś sposób, aby to naprawić. Chcę tego, jeśli mam taką pętlę, i naciśnij Control-C, aby powrócił do mojej powłoki bash.

Rory
źródło
6
Odpowiedź Dennisa jest właściwa, ale jeśli tego nie zrobiłeś, nie musisz „naciskać jak szaleniec”, wystarczy przytrzymać i pozwolić klawiaturze powtórzyć :-)
Kyle Brandt
Zawsze przytrzymuję Cntl-C, ogólnie działa dobrze.
Scott Alan Miller

Odpowiedzi:

33
for DIR in * ; do rsync -a $DIR example.com:somewhere/ || break; done

Spowoduje to również wyjście z pętli, jeśli z jakiegoś powodu pojedyncze uruchomienie rsync zakończy się niepowodzeniem.

Kenster
źródło
4
Dodatkowa wskazówka: jeśli jesteś w zagnieżdżonej pętli i chcesz całkowicie zakończyć, użyj break 2(lub zamień „2” na liczbę zagnieżdżonych pętli, które chcesz zakończyć).
Dolan Antenucci
26

Aby rozwinąć odpowiedź Dennisa, kod może wyglądać następująco:

trap "echo Exited!; exit;" SIGINT SIGTERM

Dla działającego przykładu (który zdarza się obejmować rsync), sprawdź http://gist.github.com/279849 .

Ian Greenleaf Young
źródło
Dzięki, to jest ogólne rozwiązanie, które zadziałało dla mnie
wi1
25

Możesz ustawić pułapkę dla Control-C.

trap <command> SIGINT

wykona commandnaciśnięcie Control-C. Po prostu umieść trapinstrukcję gdzieś w skrypcie w miejscu, w którym chcesz, aby stała się skuteczna.

Wstrzymano do odwołania.
źródło
6

Kiedy umieścisz ciąg poleceń w nawiasach, ciąg będzie działał jako pojedynczy proces, otrzyma SIGINT i zakończy działanie po naciśnięciu Ctrl- C:

(for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; done)

Ale! W przypadku rsyncpolecenia pozwala na wiele źródeł, więc kod, który napisałeś, byłby lepiej napisany jako:

rsync -a * example.com:somewhere/
amfetamachina
źródło
6
  1. Naciśnij, Ctrl-Zaby zawiesić skrypt;
  2. kill %%

Kredyty, wyjaśnienia i więcej szczegółów w tej odpowiedzi .

Skippy le Grand Gourou
źródło
Jest to świetne, ponieważ działa „post facto”, gdy chcesz przerwać już uruchomioną pętlę.
Nick Matteo
0

Zwykle umieszczam w mojej pętli inne polecenie, które można łatwo przerwać. Wymaga naciśnięcia dwóch klawiszy Ctrl-C.

for DIR in * ; do rsync -a $DIR example.com:somewhere/ ; sleep 1 ; done

To nie jest takie świetne rozwiązanie dla tego rsync, który prawdopodobnie chcesz szybko uruchomić. Ale działa dobrze w przypadku innych pętli, takich jak ta:

while true ; do ping -c 10 example.com ; sleep 1 ; done

Ta pętla będzie za każdym razem ponownie sprawdzać adres example.com, co jest przydatne, jeśli obserwujesz zmianę DNS.

Alan Porter
źródło