
¿Alguna vez ha escrito un script bash esperando que el servicio esté listo antes de continuar? Ese es un patrón común. Pero a veces, el servicio nunca estará en línea. Cuando esto sucede, sus scripts pueden atascarse en un bucle infinito que quizás ni siquiera se den cuenta.
Este artículo le mostrará cómo resolver este problema. Aprenderás usar timeout Comando en Bash Evite este problema.
Comencemos.
Simple until Un posible bucle que sale mal
Para fines de demostración, tomemos PostgreSQL como ejemplo.
Digamos que está escribiendo un script de implementación. Antes de ejecutar la migración de la base de datos, debe asegurarse de que se inicie PostgreSQL.
Podrías escribir:
until pg_isready -h 127.0.0.1 -p 5432; do
echo "Waiting for database..."
sleep 1
done
echo "Database is up! Running migrations..."
./run-migrations.shA primera vista, esto funciona. Sin embargo, si la base de datos nunca comienza (debido a errores tipográficos, bloqueos o mala configuración), su script esperará para siempre. Esto es arriesgado, especialmente en la automatización.
Decir hola timeout: Red de seguridad simple
Bash tiene una forma incorporada de verificar las cosas para siempre, pero no sabe cuándo rendirse. este timeout El comando solucionó esto. Si lleva demasiado tiempo, ejecuta el comando y lo mata.
Así es como funciona:
timeout 5s sleep 10
Comienza este comando sleep 10pero después de 5 segundos, timeout Envíe la señal y deténgala.
También puede verificar el código de salida después:
echo $?
124Lo que significa que se agotó.0Lo que significa que se completa normalmente.
¿Por qué no se puede usar? timeout y until Directamente
En este punto, podrías intentar algo como esto:
timeout 30s until pg_isready -h 127.0.0.1 -p 5432; do
sleep 1
donePero esto no funciona. ¿Por qué? porque until No es un pedido. Esta es una palabra clave BASH. timeout Use solo con comandos reales: comandos que se ejecutan en un proceso, p. sleep,,,,,,,,,,, para curlo ls.
La forma correcta de usar el tiempo de espera en Bash: envuélvalo en el proceso de bash
Para solucionar esto, debe envolver el bucle en un subproceso. Aquí está la forma correcta:
timeout 30s bash -c '
until pg_isready -h 127.0.0.1 -p 5432; do
echo "Waiting for database..."
sleep 1
done
'Ahora el bucle se ejecuta en un nuevo proceso bash. timeout El proceso puede ser monitoreado y asesinado si es necesario.
verificar until y timeout En el carnaval
Así es como puede verificar el PostgreSQL anterior pg_isready Ejemplo en su sistema local.
Asegúrese de tener:
- PostgreSQL instalado (
pg_isreadyLlevar contigo). - Ejecutar un servidor PostgreSQL local o remoto (o intencionalmente no ejecutar para simular una falla).
- Bash Shell (el valor predeterminado para la mayoría de los sistemas Linux/MacOS).
1. Confirmar pg_isready trabajar
correr:
pg_isready -h 127.0.0.1 -p 5432
Si PostgreSQL se está ejecutandola salida será:
127.0.0.1:5432 - accepting connections
2. Detente PostgreSQL para simular fallido
Si está utilizando Systemd:
sudo systemctl stop postgresql
Luego corre:
pg_isready -h 127.0.0.1 -p 5432
Obtendrá la siguiente salida:
127.0.0.1:5432 - no response

3. Prueba until El bucle no tiene tiempo de espera
Ejecute el siguiente código en su terminal:
until pg_isready -h 127.0.0.1 -p 5432; do
echo "Waiting for database..."
sleep 1
donePostgreSQL se reduceeste ciclo es para siempre.

4. Prueba timeout + + bash -c
Ahora ejecute el siguiente código en su terminal:
timeout 10s bash -c '
until pg_isready -h 127.0.0.1 -p 5432; do
echo "Waiting for database..."
sleep 1
done
'Comportamiento esperado:
- Correr durante 10 segundos.
- Entonces
timeoutMata el bucle. - El código de salida será
124.
$ echo $? 124

5. Comience PostgreSQL y vuelva a ejecutar
sudo systemctl start postgresql
Luego vuelva a ejecutar el bucle de envoltura de tiempo de espera:
timeout 10s bash -c '
until pg_isready -h 127.0.0.1 -p 5432; do
echo "Waiting for database..."
sleep 1
done
'Esta vez, el ciclo debe retirarse rápidamente.

Manejar errores con gracia
Siempre debe verificar si el bucle tiene éxito o tiempos de salida. Los siguientes son:
if timeout 30s bash -c '
until pg_isready -h 127.0.0.1 -p 5432; do
sleep 1
done
'; then
echo "Database is up. Starting migration..."
./run-migrations.sh
else
echo "Error: Database did not start in time."
exit 1
fiDe esta manera, sus scripts avanzan de manera segura o salen con mensajes explícitos.
Bonificación: use el bucle más corto del mostrador
Si no quieres usar timeoutesta es otra forma. Número fijo de ciclos:
for i in {1..30}; do
if pg_isready -h 127.0.0.1 -p 5432; then
echo "Database is ready."
./run-migrations.sh
exit 0
fi
sleep 1
done
echo "Database did not start after 30 seconds."
exit 1Es puro carnaval, adecuado para situaciones simples.
Puntos clave
untilEs la palabra clave bash, no un proceso.timeoutNo hay control directo de ello.- Envuelva su bucle en uno
bash -c '...'Bloques para usar con éltimeout. - Siempre verifique el estado de salida para ver si el bucle tiene éxito o falla.
- usar
pg_isready,,,,,,,,,,, paracurlu otras herramientas para verificar los servicios para la salud.
en conclusión
Los bucles infinitos pueden romper sus guiones y perder el tiempo. timeout es una herramienta simple que le proporciona control. Por envolverte until En bucle en el subproceso, hace que el script sea más potente.
Este es un pequeño truco, pero puede ahorrar horas de depuración en el futuro.
Si desea mantener sus scripts bash limpios y confiables, comience a usarlos timeout hoy.
Lectura sugerida:








