Uso del comando `sleep` en scripts Bash en Linux
El comando `sleep` en Linux suspende la ejecución de un script durante una duración precisamente definida — especificada en segundos, minutos, horas o días — usando la sintaxis `sleep [NUMBER][SUFFIX]`. Es una de las primitivas operacionalmente más críticas en los scripts Bash, que permite la limitación de velocidad, la lógica de reintentos, la sincronización de procesos y la automatización temporizada sin necesidad de planificadores externos.
A diferencia de cron o `at`, `sleep` opera completamente dentro del contexto del proceso del propio script, lo que lo convierte en la herramienta correcta cuando el retraso debe ser relativo a la finalización de un comando anterior en lugar de una hora absoluta del reloj.
Referencia de Sintaxis y Unidades de Tiempo
“`bash
sleep NUMBER[SUFFIX]
“`
| Sufijo | Unidad | Ejemplo | Equivalente en Segundos |
|---|
| ——– | ——— | —————- | ———————– |
|---|
| `s` | Segundos | `sleep 30s` | 30 |
|---|
| `m` | Minutos | `sleep 5m` | 300 |
|---|
| `h` | Horas | `sleep 2h` | 7200 |
|---|
| `d` | Días | `sleep 1d` | 86400 |
|---|
| (ninguno) | Segundos | `sleep 10` | 10 |
|---|
El sufijo es opcional. Cuando se omite, la unidad predeterminada son los segundos. En sistemas GNU/Linux (GNU coreutils), `sleep` también acepta valores de punto flotante y múltiples argumentos — una capacidad ausente en las implementaciones de BSD y macOS a menos que GNU coreutils esté instalado mediante Homebrew.
“`bash
GNU coreutils: both of these are valid
sleep 1.5
sleep 1m 30s # Equivalent to 90 seconds
“`
Nota crítica de portabilidad: POSIX solo exige segundos enteros sin sufijo. Si su script debe ejecutarse en Alpine Linux (BusyBox), macOS o AIX, limítese a `sleep INTEGER` y evite encadenar múltiples argumentos.
Casos de Uso Principales en Scripts Bash
1. Retraso Secuencial Entre Comandos
La aplicación más directa — insertar una pausa entre dos operaciones donde el segundo comando no debe comenzar hasta que una condición del mundo real haya tenido tiempo de estabilizarse:
“`bash
#!/bin/bash
echo "Restarting nginx…"
systemctl restart nginx
sleep 3
systemctl status nginx
“`
La pausa de 3 segundos aquí tiene en cuenta la secuencia de inicio asíncrono del gestor de servicios. Sin ella, `status` puede reportar un estado obsoleto capturado antes de que el proceso se inicialice completamente.
2. Bucle de Sondeo con Retroceso Exponencial
Un bucle de reintento de intervalo fijo ingenuo desperdicia recursos y puede amplificar la carga en un servicio descendente con problemas. El patrón correcto es el retroceso exponencial con fluctuación:
“`bash
#!/bin/bash
MAX_RETRIES=6
DELAY=2
for (( attempt=1; attempt<=MAX_RETRIES; attempt++ )); do
if curl -sf https://api.example.com/health > /dev/null; then
echo "Service healthy on attempt $attempt."
exit 0
fi
echo "Attempt $attempt failed. Retrying in ${DELAY}s…"
sleep "$DELAY"
DELAY=$(( DELAY * 2 ))
done
echo "Service unreachable after $MAX_RETRIES attempts." >&2
exit 1
“`
Esto duplica el tiempo de espera en cada fallo: 2s, 4s, 8s, 16s, 32s, 64s. El tiempo de espera máximo total antes de rendirse es de 126 segundos. Este patrón es estándar en scripts de despliegue en producción, comprobaciones de estado y pipelines CI/CD.
3. Llamadas a API con Límite de Velocidad
Al interactuar con APIs que aplican cuotas de solicitudes, `sleep` impone el intervalo requerido entre solicitudes:
“`bash
#!/bin/bash
API_KEY="your_key_here"
ENDPOINTS=("users" "orders" "products" "inventory")
for endpoint in "${ENDPOINTS[@]}"; do
curl -s -H "Authorization: Bearer $API_KEY"
"https://api.example.com/v1/${endpoint}"
-o "${endpoint}.json"
echo "Fetched: $endpoint"
sleep 1 # Respect 1 req/sec rate limit
done
“`
4. Ejecución de Tareas en Segundo Plano con Temporizador
Ejecutar un comando retrasado sin bloquear la sesión de shell actual requiere combinar `sleep` con la ejecución en segundo plano de subshell:
“`bash
Trigger a cache flush 60 seconds after deployment completes
( sleep 60 && redis-cli FLUSHDB ) &
echo "Cache flush scheduled. PID: $!"
“`
La variable `$!` captura el PID del subshell en segundo plano, que puede usar posteriormente con `wait` o `kill` si la tarea necesita cancelarse.
5. Bucle de Vigilancia y Monitor de Procesos
“`bash
#!/bin/bash
SERVICE="mysqld"
CHECK_INTERVAL=30
while true; do
if ! pgrep -x "$SERVICE" > /dev/null; then
echo "$(date '+%Y-%m-%d %H:%M:%S') $SERVICE not running. Restarting…"
>> /var/log/watchdog.log
systemctl start "$SERVICE"
fi
sleep "$CHECK_INTERVAL"
done
“`
Este patrón se usa en la supervisión ligera de procesos cuando un demonio supervisor completo (systemd, supervisord, s6) no está disponible o no es apropiado — común en entornos contenerizados o instancias mínimas de VPS Hosting.
6. Temporizador de Cuenta Regresiva con Retroalimentación al Usuario
Para scripts interactivos donde el operador necesita visibilidad del tiempo de espera restante:
“`bash
#!/bin/bash
COUNTDOWN=10
echo "Starting in:"
for (( i=COUNTDOWN; i>=1; i– )); do
printf "r%2d seconds remaining…" "$i"
sleep 1
done
printf "rGo! n"
“`
`printf "r"` sobreescribe la línea actual en lugar de añadir nuevas líneas, produciendo una cuenta regresiva limpia en el terminal.
`sleep` vs. Mecanismos de Temporización Alternativos
| Mecanismo | Granularidad | Bloquea el Shell | Tiempo Absoluto | Caso de Uso |
|---|
| —————– | —————– | ————– | ————— | ———————————————– |
|---|
| `sleep` | Sub-segundo (GNU) | Sí (a menos que `&`) | No | Retrasos relativos dentro de scripts |
|---|
| `cron` | 1 minuto | No | Sí | Trabajos programados recurrentes |
|---|
| `at` | 1 minuto | No | Sí | Ejecución futura de una sola vez |
|---|
| `systemd timer` | 1 segundo | No | Sí | Trabajos persistentes, registrados y con conciencia de dependencias |
|---|
| `usleep` (C) | Microsegundo | Sí | No | Precisión a nivel de kernel/C (no nativo de Bash) |
|---|
| `read -t` | Sub-segundo | Sí | No | Tiempo de espera con entrada de usuario opcional |
|---|
Cuándo usar `read -t` en lugar de `sleep`: Si su script necesita pausar pero también permitir que un usuario interrumpa o responda durante la espera, `read -t SECONDS` es la primitiva correcta. Devuelve el código de salida 1 al agotar el tiempo y 0 si el usuario presiona Enter, lo que le proporciona lógica condicional sin un proceso separado.
“`bash
echo "Press Enter to skip the 10-second wait, or wait for automatic continuation."
read -t 10 -r || true
echo "Continuing…"
“`
Precisión, Punto Flotante y Comportamiento por Plataforma
GNU `sleep` acepta fracciones decimales, lo que importa en scripts que controlan animaciones, limitan el seguimiento de registros o simulan feeds de datos en tiempo real:
“`bash
Tail a log file and print one line per 0.2 seconds (5 lines/sec)
while IFS= read -r line; do
echo "$line"
sleep 0.2
done < /var/log/app.log
“`
La duración real del sleep es un mínimo, no una garantía. El planificador del kernel puede despertar el proceso ligeramente tarde dependiendo de la carga del sistema y la resolución del temporizador (`CONFIG_HZ`). En un Servidor Dedicado con mucha carga ejecutando docenas de procesos concurrentes, un `sleep 0.1` puede pausar realmente durante 0,11–0,15 segundos. Para scripts donde esta deriva es inaceptable, use una referencia de reloj monotónico:
“`bash
#!/bin/bash
INTERVAL=5
NEXT=$(date +%s%N) # Current time in nanoseconds
while true; do
NEXT=$(( NEXT + INTERVAL * 1000000000 ))
do_work
NOW=$(date +%s%N)
REMAINING=$(( (NEXT – NOW) / 1000000 )) # Convert to milliseconds
[ "$REMAINING" -gt 0 ] && sleep "$(echo "scale=3; $REMAINING/1000" | bc)"
done
“`
Este bucle de compensación de deriva mantiene un intervalo consistente independientemente de cuánto tiempo tome `do_work`.
Manejo de Señales e Interrupción de `sleep`
Un proceso `sleep` en ejecución responde a señales. Enviar `SIGALRM` al proceso sleep lo despierta inmediatamente. De manera más práctica, presionar `Ctrl+C` envía `SIGINT` a todo el grupo de procesos, terminando tanto el script como cualquier `sleep` en primer plano.
Para que un script maneje limpiamente la interrupción durante un sleep:
“`bash
#!/bin/bash
cleanup() {
echo "Interrupted. Cleaning up…"
exit 1
}
trap cleanup SIGINT SIGTERM
echo "Waiting 60 seconds…"
sleep 60 &
SLEEP_PID=$!
wait "$SLEEP_PID"
echo "Wait complete."
“`
Al ejecutar `sleep` en segundo plano y usar `wait`, el `trap` se activa inmediatamente en `SIGINT` en lugar de diferirse hasta que el sleep se complete. Este es el patrón correcto para scripts de automatización de larga duración en servidores de producción.
Errores Prácticos y Casos Extremos
Error 1: Usar `sleep` en bucles cerrados sin condición de terminación. Un bucle `while true; do sleep 1; done` sin ruta de salida se ejecutará indefinidamente, consumiendo un slot de proceso y acumulándose en la salida de `ps`. Defina siempre un recuento máximo de iteraciones o una condición centinela.
Error 2: Asumir que `sleep` es síncrono con los subshells. Cuando bifurca un subshell con `&`, el script padre no espera a que el `sleep` del subshell se complete a menos que llame explícitamente a `wait`. Esto causa condiciones de carrera en scripts de despliegue paralelo.
Error 3: Codificar retrasos fijos para la disponibilidad del servicio. Usar `sleep 5` después de iniciar un servicio es frágil. El servicio puede estar listo en 1 segundo o puede tardar 30 segundos bajo carga. La alternativa robusta es un sondeo de disponibilidad:
“`bash
#!/bin/bash
wait_for_port() {
local host="$1" port="$2" timeout="${3:-30}"
local elapsed=0
until nc -z "$host" "$port" 2>/dev/null; do
[ "$elapsed" -ge "$timeout" ] && return 1
sleep 1
(( elapsed++ ))
done
}
systemctl start postgresql
wait_for_port localhost 5432 30 && echo "PostgreSQL ready."
“`
Error 4: Sleep de punto flotante en sistemas BusyBox. Los contenedores Alpine Linux usan el `sleep` de BusyBox, que no admite decimales. Intentar `sleep 0.5` generará un error. Valide su entorno antes de desplegar scripts que dependan de precisión sub-segundo.
Integración de `sleep` en Flujos de Trabajo Automatizados de Servidor
En un VPS con cPanel gestionado, los scripts de mantenimiento automatizado frecuentemente combinan `sleep` con cron para implementar programación sub-minuto. Dado que la resolución mínima de cron es un minuto, puede lograr intervalos de 15 segundos de esta manera:
“`bash
crontab entry — runs the script 4 times per minute
- * * * * /usr/local/bin/check_queue.sh
- * * * * sleep 15 && /usr/local/bin/check_queue.sh
- * * * * sleep 30 && /usr/local/bin/check_queue.sh
- * * * * sleep 45 && /usr/local/bin/check_queue.sh
“`
Esta técnica se usa ampliamente para procesadores de cola, comprobaciones de estado y recopiladores de métricas en infraestructura compartida donde no está permitido instalar un planificador de trabajos dedicado.
Para scripts de renovación de certificados SSL, `sleep` proporciona el retraso entre intentos cuando la propagación del desafío ACME requiere que el TTL de DNS expire antes de que la CA pueda verificar la propiedad. Si gestiona certificados en su propia infraestructura, los Certificados SSL con pipelines de renovación automatizada se benefician de intervalos de reintento precisamente ajustados.
De manera similar, los scripts de verificación de propagación de dominio — útiles después de actualizar registros a través del Registro de Dominios — usan bucles `sleep` para sondear resolvers DNS a intervalos alineados con los valores TTL esperados.
Matriz de Decisión: Elegir la Estrategia de Retraso Correcta
| Escenario | Enfoque Recomendado |
|---|
| ———————————————– | ————————————————— |
|---|
| Pausa fija entre dos comandos secuenciales | `sleep N` |
|---|
| Reintentar hasta el éxito, evitar el efecto de manada | Retroceso exponencial con `sleep` |
|---|
| Tarea recurrente cada N minutos | `cron` (no `sleep`) |
|---|
| Tarea recurrente sub-minuto | `cron` + truco de desplazamiento `sleep` |
|---|
| Retraso sin bloquear el terminal | `( sleep N && command ) &` |
|---|
| Pausa con capacidad de interrupción por el usuario | `sleep N &` + `wait $!` + `trap` |
|---|
| Comprobación de disponibilidad del servicio | Bucle de sondeo de puerto/estado con `sleep 1` por intento |
|---|
| Intervalo de alta precisión (compensación de deriva) | Referencia de reloj monotónico con `sleep` calculado |
|---|
| Retraso sub-segundo en Alpine/BusyBox | Evitar; usar segundos enteros o cambiar la imagen base |
|---|
Conclusiones Técnicas Clave
- Utilice siempre `sleep "$VARIABLE"` con comillas dobles para evitar errores de división de palabras cuando la variable contiene un decimal.
- Prefiera `sleep 1m 30s` sobre `sleep 90` para mayor legibilidad en scripts de mantenimiento de larga duración.
- Ejecute `sleep` en segundo plano con `wait` y un `trap` siempre que su script deba responder a señales durante la pausa.
- Nunca use un `sleep` codificado como sustituto de una comprobación de disponibilidad adecuada — use un bucle de sondeo con tiempo de espera.
- Valide el comportamiento de `sleep` en el sistema operativo de destino antes de desplegar scripts que usen sintaxis de punto flotante o múltiples argumentos.
- En servidores de producción, registre la marca de tiempo antes y después de llamadas largas a `sleep` para detectar la deriva del planificador en el análisis post-incidente.
- Al construir automatización en Paneles de Control VPS, confirme si el planificador de tareas del panel ya proporciona control de intervalos antes de añadir lógica `sleep` manualmente.
Preguntas Frecuentes
¿Consume CPU `sleep` mientras espera?
No. `sleep` llama a `nanosleep()` (o equivalente) a nivel del kernel, colocando el proceso en un estado de sleep interrumpible (`S` en la salida de `ps`). No consume ciclos de CPU durante la espera — solo una pequeña cantidad de memoria para la entrada del proceso en la tabla de procesos.
¿Cuál es el valor máximo aceptado por `sleep`?
En GNU/Linux, `sleep` acepta valores hasta los límites de un número de punto flotante `double`, lo que es efectivamente ilimitado para propósitos prácticos. `sleep 1d` (86400 segundos) es común; `sleep 365d` es válido. El límite práctico es el tiempo de actividad del sistema.
¿Por qué falla `sleep 0.5` en mi contenedor Docker?
Alpine Linux usa BusyBox, cuya implementación de `sleep` solo acepta segundos enteros. Cambie a una imagen base de Debian o Ubuntu, o instale GNU coreutils (`apk add coreutils`) para habilitar el soporte decimal.
¿Puedo cancelar un proceso `sleep` ejecutado en segundo plano?
Sí. Capture su PID con `SLEEP_PID=$!` inmediatamente después de ejecutarlo en segundo plano, luego use `kill "$SLEEP_PID"` para terminarlo. Si usó `( sleep N && command ) &`, matar el PID del subshell también evitará que se ejecute el comando posterior.
¿Es seguro usar `sleep` dentro del script `ExecStart` de una unidad de servicio `systemd`?
Sí, pero con advertencias. Si la unidad de servicio tiene `TimeoutStartSec` configurado, un `sleep` largo durante el inicio hará que systemd mate el servicio como un inicio fallido. Para retrasos posteriores al inicio, use `ExecStartPost` con un sondeo de disponibilidad, o configure `Type=forking` con una gestión adecuada de archivos PID en lugar de depender de `sleep` para diferir la inicialización.
