Terminer une boucle infinie

Jai une commande que je veux faire réexécuter automatiquement à chaque fois quelle se termine, jai donc exécuté quelque chose comme ceci:

while [ 1 ]; do COMMAND; done; 

mais si je ne peux pas arrêter la boucle avec Ctrl-c car cela tue juste COMMAND et pas toute la boucle.

Comment pourrais-je réaliser quelque chose de similaire mais que je peux arrêter sans avoir à fermer le terminal?

Commentaires

  • Si je ‘ m dans bash, jutilise simplement Ctrl-Z pour arrêter le travail, puis  » tue% 1  » pour le tuer.
  • Attendez juste … Linus a été cité comme disant: «Nous savons tous que Linux est génial … il fait des boucles infinies en 5 secondes. «  – alors vraiment … attendez quelques secondes de plus, cela devrait se terminer.
  • @PaulCager a fonctionné pour moi aussi! Pourquoi cela fonctionne-t-il là où Ctrl-C fonctionne non?
  • @cirosantilli il tue le travail externe (le bash  » wrapper « ). Dans certaines situations, ‘ t tuer immédiatement la  » COMMAND « , par exemple , si vous le mettez en arrière-plan, il peut se faufiler devant vivant même si le parent de ‘ est mort. Mais la boucle est morte, et que ‘ est la partie importante.

Réponse

Vérifiez létat de sortie de la commande. Si la commande sest terminée par un signal, le code de sortie sera 128 + le numéro du signal. Depuis la documentation en ligne GNU pour bash :

Pour les besoins du shell, une commande qui sort avec un statut de sortie nul a réussi. Un état de sortie différent de zéro indique un échec. Ce schéma apparemment contre-intuitif est utilisé, il existe donc une manière bien définie dindiquer le succès et diverses manières dindiquer les différents modes de défaillance. Lorsquune commande se termine sur un signal fatal dont le numéro est N, Bash utilise la valeur 128 + N comme état de sortie.

POSIX spécifie également que la valeur dune commande terminée par un signal est supérieure à 128, mais ne semble pas spécifier sa valeur exacte comme le fait GNU:

Létat de sortie dune commande qui sest terminée parce quelle a reçu un signal doit être signalé comme supérieur à 128.

Par exemple, si vous interrompez une commande avec control-C, le code de sortie sera 130, car SIGINT est le signal 2 sur les systèmes Unix. Donc:

while [ 1 ]; do COMMAND; test $? -gt 128 && break; done 

Commentaires

  • Il faut mentionner que ce nest pas garanti, en fait, de nombreuses applications ne le feront pas.
  • @Kyle Jones: pouvez-vous créer un lien vers les documents POSIX / GNU qui mentionnent cela?
  • @cirosantilli Terminé.
  • @ Merci KyleJones! Toujours en pratique ne fonctionne pas pour COMMAND = paplay alert.ogg, peut-être parce que paplay gère le signal?
  • @cirosantilli Oui, que ‘ est la raison. Si un processus gère le signal et se ferme, ce ‘ est différent du processus terminé par un signal non géré.

Réponse

Vous pouvez arrêter et mettre votre tâche en arrière-plan pendant son exécution en utilisant ctrl + z . Ensuite, vous peut tuer votre travail avec:

$ kill %1 

Où [1] est votre numéro de travail.

Commentaires

  • Voir aussi cette réponse pour des explications et plus.
  • Cette réponse relativement récente fonctionne tout simplement. a voté pour +1
  • Vous mavez beaucoup aidé. Cest ce que jai recherché dans cette question 🙂

Réponse

Je dirais quil serait peut-être préférable de mettre votre boucle infinie dans un script et dy gérer les signaux. Voici « un point de départ de base . Je suis sûr que vous voudrez le modifier en conséquence. Le script utilise trap pour capturer ctrl c (ou SIGTERM), tue la commande (jai utilisé sleep ici comme test) et quitte.

cleanup () { kill -s SIGTERM $! exit 0 } trap cleanup SIGINT SIGTERM while [ 1 ] do sleep 60 & wait $! done 

Commentaires

  • Bien. Voici ‘ comment jai utilisé cette astuce pour créer un wrapper netcat à démarrage automatique: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • si vous ajoutez cette approche trap au même script (bash) avec la boucle infinie à tuer, utilisez $$ au lieu de $! (voir ici )

Réponse

En général, je maintiens simplement Ctrl-C . Tôt ou tard, il « sinscrira entre COMMAND » s et ainsi terminer la boucle while. Peut-être existe-t-il un meilleur moyen.

Commentaires

  • Je ne sais pas pourquoi, mais cela échoue pour certaines COMMANDES comme paplay sur un fichier 1s .
  • Ça a marché pour moi
  • Que ‘ est la force brute de toutes les solutions ici. : /

Réponse

Si vous exécutez bash avec -e il se fermera dans toutes les conditions derreur:

#!/bin/bash -e false # returns 1 echo This won"t be printed 

Commentaires

  • La première ligne ici est de loin la solution la plus simple pour un script trivial sur lequel vous ‘ ne souhaitez pas passer trop de temps!

Réponse

Pourquoi pas simplement,

while [ 1 ]; do COMMAND || break; done; 

Ou lorsquil est utilisé dans un script,

#!/bin/bash while [ 1 ]; do # ctrl+c terminates COMMAND and exits the while loop # (assuming COMMAND responds to ctrl+c) COMMAND || break done; 

Commentaires

  • Solution très élégante. Mais cela ne fonctionnerait-il ‘ que si COMMAND renvoie toujours un statut de sortie réussie?
  • Oui @howardh, que ‘ est correct.

Réponse

  1. Vous pouvez toujours tuer un processus en utilisant son PID, là  » Nul besoin de fermer votre terminal
  2. Si vous voulez exécuter quelque chose dans une boucle infinie comme un démon, il vaut mieux le mettre en arrière-plan
  3. while : créera une boucle infinie et vous évitera décrire le [ 1 ]

    while :; do COMMAND; done & 

Ceci imprimera le PID. Si vous quittez votre invite en utilisant ctrl+d, la tâche d’arrière-plan ne se fermera pas, et vous pourrez plus tard tuer la tâche de n’importe où en utilisant kill PID

Si vous perdez la trace de votre PID, vous pouvez utiliser pstree -pa $USER ou pgrep -fl ".*PROCESS.*" pour vous aider à le trouver

Réponse

Je préfère une autre solution:

touch .runcmd; while [ -f ".runcmd" ]; do COMMAND; sleep 1; done 

Dans lordre pour tuer la boucle, faites simplement:

rm .runcmd && kill `pidof COMMAND` 

Réponse

Ce qui fonctionne raisonnablement eh bien pour moi, cest:

 while sleep 1; do COMMAND; done  

Cela fonctionne parce que sleep 1 reste pendant un while et sil obtient ctrl + c, il retourne avec non zéro et la boucle se terminera.

Commentaires

  • +1, le temps de sommeil peut aussi être réduit à 0.5 ou 0.1: while sleep 0.1; do COMMAND; done

Réponse

Utilisez trap

 exit_() { exit } while true do echo "running.." trap exit_ int done  

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *