Esta respuesta al comando de línea de comando para matar automáticamente un comando después de un cierto período de tiempo
propone un método de 1 línea para agotar el tiempo de espera de un comando de ejecución larga desde la línea de comando bash:
( /path/to/slow command with options ) & sleep 5 ; kill $!
Pero es posible que un comando de "ejecución prolongada" finalice antes del tiempo de espera. (Llamémoslo un comando "típicamente de larga ejecución pero a veces rápido", o tlrbsf por diversión).
Entonces, este ingenioso enfoque de 1 línea tiene un par de problemas. Primero, el sleep
no es condicional, por lo que establece un límite inferior indeseable en el tiempo que tarda la secuencia en terminar. Considere 30s o 2m o incluso 5m para dormir, cuando el comando tlrbsf termine en 2 segundos, muy indeseable. En segundo lugar, el kill
es incondicional, por lo que esta secuencia intentará matar un proceso que no se ejecuta y quejarse al respecto.
Entonces...
¿Hay alguna manera de agotar el tiempo de espera de un comando que suele ser de larga duración pero a veces rápido ( "tlrbsf" ) que
- tiene una implementación bash (la otra pregunta ya tiene respuestas de Perl y C)
- terminará en el primero de los dos: tlrbsf programa o tiempo de espera transcurrido
- no matará procesos no existentes / no en ejecución (u, opcionalmente: no se quejará de una mala eliminación)
- no tiene que ser un trazador de líneas
- puede ejecutarse bajo Cygwin o Linux
... y, para obtener puntos de bonificación, ejecuta el comando tlrbsf en primer plano y cualquier 'suspensión' o proceso adicional en segundo plano, de modo que el stdin / stdout / stderr del tlrbsf comando se pueda redirigir, como si hubiera sido correr directamente?
Si es así, por favor comparta su código. Si no, por favor explica por qué.
He pasado un tiempo tratando de hackear el ejemplo antes mencionado, pero estoy llegando al límite de mis habilidades de bash.
fuente
timeout
utilidad gnu ?timeout
¡es genial! incluso puede usar con múltiples comandos (secuencia de comandos de varias líneas): stackoverflow.com/a/61888916/658497Respuestas:
Creo que esto es precisamente lo que estás pidiendo:
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
fuente
Probablemente esté buscando el
timeout
comando en coreutils. Como es parte de coreutils, técnicamente es una solución C, pero sigue siendo coreutils.info timeout
para más detalles. Aquí hay un ejemplo:fuente
gtimeout
brew install coreutils
, y luego puede usargtimeout
.Esta solución funciona independientemente del modo de monitor bash. Puede usar la señal adecuada para finalizar su_comando
El observador mata your_command después de un tiempo de espera determinado; el script espera la tarea lenta y finaliza el observador. Tenga en cuenta que
wait
no funciona con procesos que son hijos de un shell diferente.Ejemplos:
fuente
wait
devuelve el estado de salida del proceso en el que espera. Entonces, si su comando sale dentro del tiempo asignado pero con un estado de salida distinto de cero, entonces la lógica aquí se comportará a medida que se agota el tiempo de espera, es decir, la impresiónyour_command interrupted
. En su lugar, podría hacer elwait
sin unif
y luego verificar si el$watcher
pid todavía existe, si es así, entonces sabe que no se agotó el tiempo de espera.kill
en un caso, peropkill
en el otro. Necesitaba usarpkill
ambos para que esto funcione correctamente. Esperaría que si envuelve un comando()
, deberá usarlopkill
para matarlo. Pero tal vez funciona de manera diferente si solo hay un comando dentro del()
.Ahí tienes:
puede cambiar el
SIGINT
y10
como desee;)fuente
coreutils
paquete en FreeBSD.Puede hacer esto completamente con
bash 4.3
y por encima:_timeout 5 longrunning_command args
{ _timeout 5 producer || echo KABOOM $?; } | consumer
producer | { _timeout 5 consumer1; consumer2; }
Ejemplo:
{ while date; do sleep .3; done; } | _timeout 5 cat | less
Necesita Bash 4.3 para
wait -n
Si no necesita el código de retorno, esto puede simplificarse aún más:
Notas:
En sentido estricto no es necesario el
;
en; )
, sin embargo, hace algo más consistente a la; }
-case. Yset +b
probablemente también se pueda dejar de lado, pero es mejor prevenir que curar.Excepto
--forground
(probablemente) puede implementar todos lostimeout
soportes de variantes .--preserve-status
Sin embargo, es un poco difícil. Esto se deja como un ejercicio para el lector;)Esta receta se puede usar "naturalmente" en la cáscara (tan natural como para
flock fd
):Sin embargo, como se explicó anteriormente, no puede reexportar las variables de entorno al shell envolvente de esta manera de forma natural.
Editar:
Ejemplo del mundo real: Tiempo de espera
__git_ps1
en caso de que tarde demasiado (para cosas como enlaces SSHFS lentos):Edit2: Bugfix. Me di cuenta de que
exit 137
no es necesario y hace_timeout
no confiable al mismo tiempo.Edit3:
git
es un disco duro, por lo que necesita un doble truco para funcionar satisfactoriamente.Edit4: Olvidé un
_
en el primero_timeout
para el ejemplo GIT del mundo real.fuente
cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status.
De: tiswww.case.edu/php/chet/bash/NEWSPrefiero "timelimit", que tiene un paquete al menos en debian.
http://devel.ringlet.net/sysutils/timelimit/
Es un poco mejor que el "tiempo de espera" de coreutils porque imprime algo al finalizar el proceso, y también envía SIGKILL después de un tiempo por defecto.
fuente
timelimit -t1 ./a_forking_prog
matar solo uno de los dos procesos), pero el tiempo de espera funciona.Para agotar el tiempo de espera
slowcommand
después de 1 segundo:timeout 1 slowcommand || echo "I failed, perhaps due to time out"
Para determinar si el comando agotó el tiempo de espera o falló por sus propios motivos, verifique si el código de estado es 124:
Tenga en cuenta que cuando el estado de salida es 124, no sabe si se agotó el tiempo de espera debido a su
timeout
comando, o si el comando en sí terminó debido a alguna lógica interna de tiempo de espera propio y luego devolvió 124. Puede asumir con seguridad en cualquier caso , sin embargo, que ocurrió un tiempo de espera de algún tipo.fuente
Consulte también el script http://www.pixelbeat.org/scripts/timeout cuya funcionalidad se ha integrado en los nuevos coreutils
fuente
Un poco hacky, pero funciona. No funciona si tienes otros procesos en primer plano (¡por favor, ayúdame a solucionar esto!)
En realidad, creo que puedes revertirlo, cumpliendo con tus criterios de 'bonificación':
fuente
el tiempo de espera es probablemente el primer enfoque para intentar. Es posible que necesite una notificación u otro comando para ejecutar si se agota el tiempo de espera. Después de bastante buscar y experimentar, se me ocurrió este script bash :
fuente
Script simple con claridad de código. Guardar en
/usr/local/bin/run
:Se agota el tiempo de espera de un comando que se ejecuta demasiado tiempo:
Termina inmediatamente para un comando que completa:
fuente
Si ya sabe el nombre del programa (supongamos
program
) que finalizará después del tiempo de espera (como ejemplo,3
segundos), puedo contribuir con una solución alternativa simple y algo sucia:Esto funciona perfectamente si llamo procesos de referencia con llamadas al sistema.
fuente
argv[0]
, quizás con otros hacks para hacer más espacio).(sleep 3 && docker stop <container>) &
funcionó muy bien. ¡Gracias!{ sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"
esta manera, matará solo trabajos en el shell actual.También está
cratimeout
Martin Cracauer (escrito en C para sistemas Unix y Linux).fuente
OS X todavía no usa bash 4, ni tiene / usr / bin / timeout, así que aquí hay una función que funciona en OS X sin home-brew o macports que es similar a / usr / bin / timeout (basado en Tino's responder). La validación de parámetros, la ayuda, el uso y el soporte para otras señales son un ejercicio para el lector.
fuente
En el 99% de los casos, la respuesta NO es implementar ninguna lógica de tiempo de espera. La lógica de tiempo de espera es, en casi cualquier situación, una señal de advertencia roja de que algo más está mal y, en su lugar, debe solucionarse .
¿Su proceso se cuelga o se rompe después de n segundos a veces? Luego descubra por qué y solucione eso en su lugar.
Por otro lado, para hacer bien la solución de Strager, debe usar esperar "$ SPID" en lugar de fg 1, ya que en los scripts no tiene control de trabajo (e intentar activarlo es una estupidez). Además, fg 1 se basa en el hecho de que no inició ningún otro trabajo anteriormente en el script, lo cual es una mala suposición.
fuente
Se me presentó un problema para preservar el contexto de shell y permitir tiempos de espera, el único problema con él es que detendrá la ejecución del script en el tiempo de espera, pero está bien con las necesidades que se me presentaron:
con las salidas:
por supuesto, supongo que había un directorio llamado
scripts
fuente
fuente
Mi problema fue quizás un poco diferente: inicio un comando a través de ssh en una máquina remota y quiero matar el shell y los niños si el comando se cuelga.
Ahora uso lo siguiente:
De esta forma, el comando devuelve 255 cuando hubo un tiempo de espera o el código de retorno del comando en caso de éxito
Tenga en cuenta que los procesos de eliminación de una sesión ssh se manejan de manera diferente a un shell interactivo. Pero también puede usar la opción -t para ssh para asignar un pseudo terminal, por lo que actúa como un shell interactivo
fuente
Aquí hay una versión que no se basa en generar un proceso hijo: necesitaba un script independiente que integrara esta funcionalidad. También realiza un intervalo de sondeo fraccional, por lo que puede sondear más rápido. se hubiera preferido el tiempo de espera, pero estoy atascado en un servidor antiguo
fuente
Una forma muy simplista:
Con pkill (opción -f ) puede matar su comando específico con argumentos o especificar -n para evitar matar el proceso anterior.
fuente
Sobre la base de la respuesta de @ loup ...
Si desea agotar el tiempo de espera de un proceso y silenciar la salida kill job / pid, ejecute:
Esto pone el proceso en segundo plano en una subshell para que no vea la salida del trabajo.
fuente
Tengo un trabajo cron que llama un script php y, a veces, se atasca en el script php. Esta solución fue perfecta para mí.
Yo suelo:
fuente
scripttimeout
?