Comando de tiempo de espera en Bash

Faaiq Bilal 15 febrero 2024
  1. el comando timeout en Bash
  2. Use tiempo de espera con la señal SIGKILL en Bash
Comando de tiempo de espera en Bash

Este artículo es una guía fácil para configurar un tiempo de espera para programas específicos utilizando el comando timeout del paquete coreutils de GNU en Bash.

el comando timeout en Bash

En muchas situaciones, como obtener datos de un servidor o ejecutar una función o programa con entradas aleatorias, el programa o función puede ejecutarse durante mucho tiempo o indefinidamente.

En tales casos, es fundamental detener el programa y evitar que pierda más tiempo y recursos.

Aquí es donde entra en juego una funcionalidad de tiempo de espera. El usuario define un límite de tiempo y luego se permite que el programa se ejecute hasta que finalice con éxito, y si tarda demasiado hasta el límite de tiempo definido por el usuario, entonces se cancela.

La funcionalidad de tiempo de espera suele estar integrada en la mayoría de los lenguajes de programación. Sin embargo, para Bash, no está integrado y es parte de un paquete externo llamado coreutils.

Este paquete es desarrollado y mantenido por GNU y contiene implementaciones de muchas utilidades básicas.

El paquete coreutils se puede instalar simplemente ejecutando el comando sudo apt-get install -y coreutils en sistemas LINUX.

Primero debe tener Homebrew instalado para obtener los coreutils en los sistemas macOS. Para obtener Homebrew, ejecute el siguiente comando en la terminal de comandos.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Después de la instalación completa de Homebrew, ejecute el siguiente comando.

brew install coreutils
Note
Para los comandos coreutils en macOS, todos los comandos tendrán un prefijo g antes del nombre (por ejemplo, gdir o gtimeout).

Si tiene instalado el paquete coreutils, simplemente puede usar la función timeout, por ejemplo:

timeout 10 ping google.com

El comando anterior genera:

usar el comando de tiempo de espera

La utilidad ping en Bash está integrada y continúa ejecutándose hasta que se interrumpe manualmente. Por defecto, ping envía un paquete cada 1 segundo.

Como se vio arriba, el comando tiempo de espera elimina el ping después de 10 segundos, ya que el número justo después del comando tiempo de espera es el límite de tiempo.

Por lo tanto, el comando tiempo de espera 10 cmd1 significa que cmd1 se ejecutará hasta que se complete con éxito o 10 segundos, lo que ocurra primero. La unidad de tiempo para el comando timeout es en segundos.

Para utilizar un valor de tiempo medido en minutos, horas o días, agregue una m, una h o una d, respectivamente.

Por ejemplo, para establecer un tiempo de espera de 2 minutos:

timeout 2m programToRun

Cabe señalar que el estado de salida para un tiempo de espera es 124 cuando el proceso se agota. En el siguiente ejemplo, usaremos esto para verificar si el proceso ha expirado o no.

timeout 1 ping 8.8.8.8 -w3
EXIT_STATUS=$?
if [ $EXIT_STATUS -eq 124 ]
then
echo 'Process timed out!'
else
echo 'Process did not timeout.'
fi
exit $EXIT_STATUS

En el ejemplo ilustrado anteriormente, si el proceso no se completa en 1 segundo, el proceso expirará. La extensión -w3 indica que se hará ping a la dirección tres veces.

Por lo tanto, este proceso siempre expirará, dando el siguiente resultado.

PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=57 time=40.4 ms
Process timed out!

Es importante tener en cuenta que cualquier tiempo de espera interno también dará como resultado el mismo estado de salida (124). Por lo tanto, esta salida indica que el proceso se agotó utilizando nuestro tiempo de espera especificado o algún tiempo de espera interno lo hizo terminar.

Use tiempo de espera con la señal SIGKILL en Bash

Normalmente, la función timeout envía una señal SIGTERM para detener la ejecución de un programa cuando se alcanza el límite de tiempo. El problema es que algunos programas pueden ignorar la señal SIGTERM y seguir funcionando.

Aquí es donde entra la señal SIGKILL; inmediatamente deja de ejecutar un proceso y todos sus procesos secundarios y no se puede bloquear ni ignorar. Para usar un tiempo de espera con SIGKILL, debemos agregar la bandera -s.

Por ejemplo:

timeout -s SIGKILL 10 programToRun

Cuando no se ejecuta timeout directamente desde el shell, como cuando se ejecuta desde un script, es importante agregar --foreground al comando timeout.

Se pueden usar muchas alternativas al comando tiempo de espera, todas basadas principalmente en la misma lógica de usar alguna señal de interrupción con sleep y luego ejecutar el comando o programa requerido, que se detendrá tan pronto como finalice sleep.

Ejemplo:

(sleep 2 && killall prog) & ./prog

El código anterior matará todos los procesos de prog después de 2 segundos si el prog no ha completado su ejecución. Tales soluciones pueden funcionar, pero no son tan seguras y confiables como el comando tiempo de espera, por lo que siempre es mejor usar tiempo de espera en su lugar.