Terminando un bucle infinito

Tengo un comando que quiero que se ejecute de nuevo automáticamente cada vez que termine, así que ejecuté algo como esto:

while [ 1 ]; do COMMAND; done; 

pero si no puedo detener el bucle con Ctrl-c , eso acaba con COMMAND y no el ciclo completo.

¿Cómo podría lograr algo similar pero que pueda detener sin tener que cerrar la terminal?

Comentarios

  • Si ‘ m en bash, simplemente uso Ctrl-Z para detener el trabajo y luego » matar% 1 » para matarlo.
  • Solo espera … Linus fue citado diciendo: “Todos sabemos que Linux es genial … hace bucles infinitos en 5 segundos «. – así que realmente … solo espera unos segundos más, debería completarse.
  • ¡@PaulCager también funcionó para mí! ¿Por qué funciona donde Ctrl-C lo hace? no?
  • @cirosantilli mata el trabajo externo (el bash » envoltorio «). En algunas situaciones, ganó ‘ t eliminar inmediatamente el » COMMAND «, por ejemplo , si lo pone en segundo plano, puede escabullirse vivo incluso si ‘ s padre está muerto. Pero el ciclo está muerto, y esa ‘ es la parte importante.

Respuesta

Verifique el estado de salida del comando. Si el comando terminó con una señal, el código de salida será 128 + el número de la señal. De la documentación en línea de GNU para bash :

Para los propósitos del shell, un comando que sale con un estado de salida cero ha tenido éxito. Un estado de salida distinto de cero indica falla. Este esquema aparentemente contrario a la intuición se utiliza para que haya una forma bien definida de indicar el éxito y una variedad de formas de indicar varios modos de falla. Cuando un comando termina en una señal fatal cuyo número es N, Bash usa el valor 128 + N como estado de salida.

POSIX también especifica que el valor de un comando que termina con una señal es mayor que 128, pero no parece especificar su valor exacto como lo hace GNU:

El estado de salida de un comando que terminó porque recibió una señal se informará como mayor que 128.

Por ejemplo, si interrumpe un comando con control-C, el código de salida será 130, porque SIGINT es la señal 2 en los sistemas Unix. Entonces:

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

Comentarios

  • Debe mencionarse que esto no está garantizado, de hecho, muchas aplicaciones no hacen esto.
  • @Kyle Jones: ¿puede vincular a los documentos POSIX / GNU que mencionan eso?
  • @cirosantilli Done.
  • @ ¡Gracias KyleJones! ¿Todavía en la práctica no funciona para COMMAND = paplay alert.ogg, tal vez porque paplay maneja la señal?
  • @cirosantilli Sí, esa ‘ es la razón. Si un proceso maneja la señal y se cierra, eso ‘ es diferente al proceso que está siendo terminado por una señal no manejada.

Respuesta

Puede detener y poner su trabajo en segundo plano mientras se ejecuta usando ctrl + z . Luego puede acabar con su trabajo con:

$ kill %1 

Donde [1] es su número de trabajo.

Comentarios

  • Consulte también esta respuesta para obtener explicaciones y más.
  • Esta respuesta relativamente reciente simplemente funciona. Necesita ser Upvoted. +1
  • Me ayudaste mucho. Esto es lo que he buscado en esta pregunta 🙂

Responder

Yo diría que sería mejor poner su bucle infinito en un script y manejar las señales allí. Aquí «un punto de partida básico . Estoy seguro de que querrá modificarlo para adaptarlo. La secuencia de comandos usa trap para capturar ctrl c (o SIGTERM), elimina el comando («he usado sleep aquí como prueba) y sale.

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

Comentarios

  • Genial. Aquí ‘ s cómo utilicé este consejo para hacer un contenedor netcat de inicio automático: trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
  • si agrega este trap enfoque al mismo script (bash) con el bucle infinito que se eliminará, use $$ en lugar de $! (consulte aquí )

Responder

Por lo general, mantengo presionada la tecla Ctrl-C . Tarde o temprano «se registrará entre COMMAND» sy así terminar el bucle while. Tal vez haya una mejor manera.

Comentarios

  • No estoy seguro de por qué, pero falla para ciertos COMANDOS como paplay en un archivo 1s .
  • Me funcionó
  • Que ‘ es la fuerza bruta de todas las soluciones aquí. : /

Responder

Si ejecuta bash con -e saldrá en cualquier condición de error:

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

Comentarios

  • La primera línea aquí es de lejos la solución más simple para una secuencia de comandos trivial en la que ‘ no desea dedicar demasiado tiempo.

Respuesta

Por qué no simplemente,

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

O cuando se usa en 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; 

Comentarios

  • Solución muy elegante. ¿Pero no ‘ esto solo funcionaría si COMMAND siempre devuelve un estado de salida exitoso?
  • Sí @howardh, eso ‘ s correcto.

Respuesta

  1. Siempre puede matar un proceso usando su PID, ahí » s no es necesario cerrar tu terminal
  2. Si quieres ejecutar algo en un bucle infinito como un demonio, entonces es mejor que lo pongas en segundo plano
  3. while : creará un bucle infinito y te ahorrará escribir el [ 1 ]

    while :; do COMMAND; done & 

Esto imprimirá el PID. Si sale del mensaje con ctrl+d, el trabajo en segundo plano no se cerrará, y luego podrá finalizar el trabajo desde cualquier lugar usando kill PID

Si pierde la pista de su PID, puede usar pstree -pa $USER o pgrep -fl ".*PROCESS.*" para encontrarlo

Respuesta

Prefiero otra solución:

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

En orden para cerrar el ciclo, simplemente haga:

rm .runcmd && kill `pidof COMMAND` 

Responder

Lo que funciona razonablemente bueno para mí es:

 while sleep 1; do COMMAND; done  

Esto funciona porque el sueño 1 se queda por un while y si obtiene ctrl + c, regresa con un valor distinto de cero y el ciclo terminará.

Comentarios

  • +1, el tiempo de suspensión también puede ser reducido a 0.5 o 0.1: while sleep 0.1; do COMMAND; done

Respuesta

Utilice trap

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

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *