Bash Loop - Comment arrêter la boucle lorsque j'appuie sur Control-C dans une commande?

35

Je suis en train de resynchroniser quelques annuaires. J'ai un terminal bash ouvert et j'exécute quelque chose comme ceci:

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

Cependant, si je veux tout arrêter, j'appuie sur Control-C. Cela arrête le rsync, mais ensuite il continue à aller au suivant. Dans ce cas, je réalise ce qui s’est passé et appuie ensuite sur Control-C comme un fou jusqu’à ce que tout fonctionne à nouveau.

Y at-il un moyen de "réparer" cela. Je le veux, donc si j'ai une boucle comme celle-là et que j'appuie sur Ctrl-C, cela me ramènera à mon shell bash.

Rory
la source
6
La réponse de Dennis est la bonne, mais si vous ne le faites pas, vous n'avez pas à le presser comme un fou, tenez-le et laissez le clavier répéter le traitement :-)
Kyle Brandt
Je tiens toujours juste Cntl-C, fonctionne généralement bien.
Scott Alan Miller

Réponses:

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

Cela permettra également de quitter la boucle si une exécution individuelle de rsync échoue pour une raison quelconque.

Kenster
la source
4
Conseil supplémentaire: si vous êtes dans une boucle imbriquée et que vous souhaitez terminer complètement, utilisez break 2(ou remplacez "2" par le nombre de boucles imbriquées que vous souhaitez terminer).
Dolan Antenucci
26

Pour développer la réponse de Dennis, votre code pourrait ressembler à ceci:

trap "echo Exited!; exit;" SIGINT SIGTERM

Pour un exemple pratique (impliquant rsync), consultez http://gist.github.com/279849 .

Ian Greenleaf Young
la source
Merci, ceci est une solution générique qui a fonctionné pour moi
wi1
25

Vous pouvez définir une interruption pour Control-C.

trap <command> SIGINT

s'exécutera commandlorsque Control-C sera enfoncé. Il suffit de placer la trapdéclaration quelque part dans votre script à un point où vous souhaitez qu'elle devienne effective.

En pause jusqu'à nouvel ordre.
la source
7
  1. Appuyez sur Ctrl-Zpour suspendre le script.
  2. kill %%

Crédits, explications et plus de détails dans cette réponse .

Skippy le Grand Gourou
la source
C’est génial parce que cela fonctionne "post facto" lorsque vous souhaitez interrompre une boucle longue déjà commencée.
Nick Matteo le
la meilleure réponse, merci!
Kostanos Il y a
6

Lorsque vous mettez une chaîne de commandes entre parenthèses, la chaîne agira comme un processus unique, recevra le SIGINT et se terminera lorsque vous frapperez Ctrl- C:

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

Mais! Dans le cas de la rsynccommande, elle autorise plusieurs sources. Le code que vous avez écrit serait ainsi mieux écrit:

rsync -a * example.com:somewhere/
amphétamachine
la source
0

J'ai tendance à mettre une autre commande dans ma boucle qui peut facilement être interrompue. Il faut appuyer sur deux touches Ctrl-C.

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

Ce n'est pas une excellente solution pour ce rsync, que vous voudrez probablement exécuter rapidement. Mais cela fonctionne bien pour d'autres boucles, comme celle-ci:

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

Cette boucle recherchera à chaque fois l'adresse de example.com à travers la boucle, ce qui est utile si vous surveillez un changement DNS.

Alan Porter
la source