En realidad, esto es lo que timeout
es para:
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.
[email protected]:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
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:
timeout
siempre usaSIGKILL
como señal de último recurso.timeout
no tiene ninguna funcionalidad para salir con una señal cuando el programa hijo 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 para eso.
Como timeout
está instalado en más sistemas de forma predeterminada (coreutils
es un paquete estándar en muchas distribuciones), le sugiero que lo use a menos que necesite la funcionalidad adicional provista por timelimit
.
Puro bash
incorporado, sin coreutils
Descubrí que esta solución funciona en bash
confiando en un incorporado comando sin llamar a un ejecutable externo. Funciona en sistemas donde eventualmente ni siquiera se han instalado los coreutils
YourCommand & read -t 300 ; kill $! # 1st version
YourCommand & read -t 300 || kill $! # 2nd version
Explicaciones :como siempre cuando envías un comando en segundo plano 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 proyectiles es la presencia del incorporado comando read
y de la opción -t
.En la primera versión, si el usuario no completa 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.
La segunda versión funciona como la primera, pero puede anular el tiempo de espera de eliminación simplemente presionando enter .
De hecho, el operador or ||
ejecuta el kill
declaración sólo si el read
El comando sale con un código de retorno diferente de cero, como cuando se agota el tiempo de espera. Si presiona ingresar antes de ese momento, devolverá 0 y no eliminará su comando anterior.
Soluciones Coreutils
Cuando coreutils están presentes en su sistema y no necesita ahorrar tiempo ni recursos para llamar a un programa externo, timeout
y sleep
y ambas son formas perfectas de alcanzar su objetivo.
timeout
El uso de timeout
es sencillo
Eventualmente, puede considerar usar también el -k
opción para enviar una señal de eliminación adicional si falla la primera.
timeout 5m YourCommand # 3rd version
sleep
Con sleep
puedes usar tu fantasía o tomar algunas inspiraciones. Tenga en cuenta que puede dejar su comando en segundo plano o en primer plano (por ejemplo, top
generalmente necesita 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
Por supuesto, en cada versión puedes enviar la señal de muerte que necesitas, desde la predeterminada hasta la extrema. kill -9
, para usarse solo cuando sea realmente necesario.
Referencias
- [1] Los Coreutils
- [2] La guía para principiantes de Bash
- [3] Las preguntas frecuentes de Bash