¿Cuál es una manera simple de dejar que un comando se ejecute durante 5 minutos? [duplicar]

Respuestas:

67

Hay (al menos) dos programas que proporcionan esta funcionalidad:

NOMBRE

timelimit - limitar efectivamente el tiempo de ejecución absoluto de un proceso

SINOPSIS

timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]

y

NOMBRE

timeout - ejecutar un comando con un límite de tiempo

SINOPSIS

timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]

Se empaquetan de la siguiente manera:

$ dlocate `which timeout timelimit`
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout

Comparación:

/-----------------------------+------------+----------------\
|            Feature          |  timelimit |     timeout    |
+=============================+============+================+
|   time to run               | -t time    | first argument |
+-----------------------------+------------+----------------+
|   terminate signal          | -s signal  | -s signal      |
+-----------------------------+------------+----------------+
|   grace period              | -T time    | -k time        |
+-----------------------------+------------+----------------+
|   kill signal               | -S signal  | (note 1)       |
+-----------------------------+------------+----------------+
|   propagate signals         | -p         | (note 2)       |
\-----------------------------+------------+----------------/

Notas:

  1. timeoutsiempre se usa SIGKILLcomo señal de último recurso.
  2. timeout no tiene ninguna funcionalidad para salir con una señal cuando el programa secundario lo hace.

El estado de salida de los dos programas difiere, pero eso es difícil de resumir claramente, por lo que le sugiero que consulte las páginas del manual.

Como timeoutestá instalado en más sistemas de manera predeterminada ( coreutilses un paquete estándar en muchas distribuciones), le sugiero que lo use a menos que necesite la funcionalidad adicional proporcionada por timelimit.

Toby Speight
fuente
10
¿Por qué usarías uno en lugar del otro?
Brice M. Dempsey
2
@ BriceM.Dempsey En mi máquina local, el tiempo de espera está presente, pero el límite de tiempo no (aunque está disponible en el repositorio). Entonces, si uno de ellos viene preinstalado ... Aparte de eso, solo mirando las firmas de métodos puedo ver que hacen cosas diferentes y tienen diferentes casos de uso.
Benubird
Tenga en cuenta que existen al menos dos implementaciones de timelimit. Consulte Cómo puedo eliminar un proceso y asegúrese de que el PID no se haya reutilizado para obtener más información sobre ellos y el tiempo de espera de GNU.
sch
1
@ BriceM.Dempsey timeoutestá incluido en GNU coreutils , timelimitno lo está. Puede haber instalado ninguno, uno o ambos. Para el segundo, se informa que timelimit ejecuta un comando y finaliza el proceso generado después de un tiempo determinado con una señal dada. Primero se envía una señal de "advertencia" , luego, después de un tiempo de espera, una señal de "muerte", similar a la forma en que init (8) opera en el apagado. Entonces, incluso un comportamiento diferente en el medio .
Hastur
Dado que GNU coreutils está preinstalado en cada GNU / Linux, este timeoutes el camino a seguir.
rexkogitans
87

En realidad, esto es para lo que timeoutsirve:

TIMEOUT(1)                          User Commands                         TIMEOUT(1)

NAME
       timeout - run a command with a time limit

SYNOPSIS
       timeout [OPTION] DURATION COMMAND [ARG]...
       timeout [OPTION]

DESCRIPTION
       Start COMMAND, and kill it if still running after DURATION.

lx@lxtp:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
Gombai Sándor
fuente
16

Puro bashincorporado, sin coreutils

Descubrí que esta solución funciona al bashconfiar en un comando incorporado sin llamar a un ejecutable externo. Funciona en sistemas donde eventualmente ni siquiera se han instalado los coreutils [ 1 ]

YourCommand & read -t 300 ;  kill $!                           # 1st version
YourCommand & read -t 300 || kill $!                           # 2nd version 

Explicaciones : como de costumbre cuando se envía un comando en el fondo con &, su PID se almacena en la variable interna $!(presente en la versión moderna de dash, csh, bash, tcsh, zsh...).
Lo que realmente marca la diferencia entre los shells es la presencia del comando incorporado read[ 2 ] y de la opción -t. En la primera versión, si el usuario no completará una línea de entrada antes de la cantidad de segundos especificada, la instrucción finalizará y se generará un código de retorno de error.

-t TIEMPO DE ESPERA Causa la lectura del tiempo de espera y devuelve el fallo si no se lee una línea completa de entrada en segundos de TIEMPO DE ESPERA.

La segunda versión funciona como la primera, pero puede abortar el tiempo de espera de matar simplemente presionando enter.
De hecho, el operador o ||ejecuta la killinstrucción solo si el readcomando sale con un código de retorno diferente de cero, como cuando expira el tiempo de espera. Si presiona enterantes de ese momento, devolverá 0 y no matará su comando anterior.


Soluciones Coreutils [ 1 ]

Cuando coreutils está presente en su sistema y no tiene necesidad de ahorrar tiempo y recursos para llamar a un programa externo, timeouty sleepambas son formas perfectas de alcanzar su objetivo.

timeoutEl uso de timeoutes sencillo.
Eventualmente, puede considerar usar también la -kopción de enviar una señal de muerte adicional si la primera falla.

timeout 5m YourCommand                                         # 3rd version 

sleep Con sleepusted puede usar su fantasía o tomar algunas inspiraciones [ 3 ] . Tenga en cuenta que puede dejar su comando en segundo plano o en primer plano (por ejemplo, topgeneralmente debe estar en primer plano).

YourCommand & sleep 5m; kill $!                                # 4th Background
YourCommand & pid=$! ; (sleep 5m; kill $pid;) &                # 5th Background

bash -c '(sleep 5m; kill $$) & exec YourCommand'               # 6th Foreground
(cmdpid=$BASHPID; (sleep 5m; kill $cmdpid) & exec YourCommand) # 7th Foreground

Explicaciones

  • En la cuarta versión, ejecuta en segundo plano y YourCommandluego su shell sleepes de 5 minutos. Cuando finalice, el último proceso en segundo plano ( $!) se eliminará. Tú detienes tu caparazón.
  • En la quinta versión, en su lugar, ejecuta en segundo plano YourCommandy almacena inmediatamente ese PID en la variable $pid. Luego ejecutas en segundo plano una siesta de 5 minutos y su consecuente comando que matará ese PID almacenado. Como envió este grupo de comandos en segundo plano, no detiene su shell. Necesita almacenar el PID en una variable porque el valor de $!se puede actualizar mediante una ejecución eventual de otro programa en segundo plano. En palabras simples, evitas el riesgo de matar el proceso incorrecto o ningún proceso en absoluto.
  • En la sexta versión se llama un nuevo shell de bash que se suicidará en 5 minutos $$, luego se ejecuta su comando que permanece en primer plano.
  • En la séptima versión se invoca una subshell ()que almacena su PID en una variable ( cmdpid) y se suicida con otra subshell enviada en ejecución en segundo plano, luego ejecuta YourCommand en primer plano.

Por supuesto, en cada versión puede enviar la señal de apagado que necesita, desde la predeterminada hasta el extremo kill -9 , para usarla solo cuando realmente la necesite.

Referencias

  • [ 1 ] Los Coreutils
  • [ 2 ] La guía para principiantes de Bash
  • [ 3 ] El BashFAQ
Hastur
fuente
2
"Con el sueño puedes usar tu fantasía o inspirarte [enlace a Bash FAQ]" +1 #thatsenoughinternetfortoday
joeytwiddle
11

Para su caso particular, la mayoría de las implementaciones de pingsoporte -co --countpara finalizar después de un número particular de pings:

ping -c 300 host.example.com

Para una solución más general, vea las otras respuestas.

Toby Speight
fuente
77
Me da la impresión de que OP acaba de proporcionar pingun ejemplo concreto. No quiere una solución caso por caso para cada programa diferente.
user1717828
8

Puedes hacerlo con un script simple como este:

#!/bin/bash

#
# $1 is the time to let the program run, and $2, $3, ... are the command itself.
#

"${@:2}" &
PID=$!
sleep "${@:1:1}"
kill -2 $PID

(señal SIGINT = 2 utilizada según la sugerencia de Matija Nalis en el comentario a continuación).

Una explicación de la expresión bash (¿poco común?) $@:...: Los parámetros posicionales, ( $*, $@, "$*", "$@") admiten la siguiente especificación adicional, por ejemplo:

"${@:START:COUNT}"

lo que significa: de todos los parámetros, tomar COUNT de ellos, el primero en ser tomado es el de la posición START; Si se omite COUNT, llévelos todos hasta el final, comenzando con la posición STARTth. Recuerde que ese $0es el nombre del programa. Si START es negativo, comience a contar desde el final y recuerde que COUNT no puede ser negativo, por lo tanto, el último argumento es "${@:-1}". Además, casi siempre incluye los parámetros posicionales dentro de las comillas dobles.

MariusMatutiae
fuente
1
Probablemente diseñaría el script para tomar el tiempo como el primer o el último argumento, y ejecutar todos los otros argumentos como el comando. Dejar bash dividir palabras $1es bastante asqueroso. Además, podrías simplemente sleep "$1"o algo así countdown.
Peter Cordes
1
@PeterCordes Hecho, según sus deseos.
MariusMatutiae
El tiempo en el primer argumento le permite hacerlo time=$1; shift, y luego no necesita la sintaxis de corte de matriz para los parámetros posicionales. Pero sí, eso es mucho más simple.
Peter Cordes
1
@PeterCordes De acuerdo, pero me pediste ver si conocía una forma más segura de hacer esto y si había sido flojo, o si simplemente era ignorante. jajaja
MariusMatutiae
Como el póster preguntó específicamente sobre el programa con el que se puede interrumpir ctrl-c, probablemente sea mejor intentarlo en kill -INTlugar de kill -9(o al menos intentarlo -9solo después de unos segundos si el primero no tuvo éxito; le da al programa la oportunidad de salir limpiamente y no dejar archivos temporales etc alrededor)
Matija Nalis
5

Como mencionas pingen tu ejemplo; Este comando tiene algunas opciones para detenerse después de un período de tiempo específico:

  • w fecha límite Especifique un tiempo de espera, en segundos, antes de que salga el ping, independientemente de cuántos paquetes se hayan enviado o recibido. En este caso, el ping no se detiene después de enviar el paquete de conteo , espera a que venza la fecha límite o hasta que se respondan las sondas de conteo o alguna notificación de error de la red.
  • W timeout Tiempo para esperar una respuesta, en segundos. La opción afecta solo el tiempo de espera en ausencia de respuestas; de lo contrario, el ping espera dos RTT.

-man ping

usuario2428118
fuente