Utiliser la commande `sleep` dans les scripts Bash sous Linux
La commande `sleep` sous Linux suspend l’exécution d’un script pendant une durée précisément définie — spécifiée en secondes, minutes, heures ou jours — en utilisant la syntaxe `sleep [NUMBER][SUFFIX]`. C’est l’une des primitives les plus essentielles dans les scripts Bash, permettant la limitation de débit, la logique de nouvelle tentative, la synchronisation des processus et l’automatisation temporisée sans nécessiter de planificateurs externes.
Contrairement à cron ou `at`, `sleep` fonctionne entièrement dans le contexte du processus propre au script, ce qui en fait l’outil approprié lorsque le délai doit être relatif à l’achèvement d’une commande précédente plutôt qu’à une heure absolue.
Syntaxe et référence des unités de temps
“`bash
sleep NUMBER[SUFFIX]
“`
| Suffixe | Unité | Exemple | Équivalent en secondes |
|---|
| ——– | ——— | —————- | ———————– |
|---|
| `s` | Secondes | `sleep 30s` | 30 |
|---|
| `m` | Minutes | `sleep 5m` | 300 |
|---|
| `h` | Heures | `sleep 2h` | 7200 |
|---|
| `d` | Jours | `sleep 1d` | 86400 |
|---|
| (aucun) | Secondes | `sleep 10` | 10 |
|---|
Le suffixe est facultatif. Lorsqu’il est omis, l’unité par défaut est les secondes. Sur les systèmes GNU/Linux (GNU coreutils), `sleep` accepte également les valeurs à virgule flottante et les arguments multiples — une fonctionnalité absente des implémentations BSD et macOS à moins que GNU coreutils ne soit installé via Homebrew.
“`bash
GNU coreutils: both of these are valid
sleep 1.5
sleep 1m 30s # Equivalent to 90 seconds
“`
Note critique de portabilité : POSIX ne mandate que des secondes entières sans suffixe. Si votre script doit s’exécuter sur Alpine Linux (BusyBox), macOS ou AIX, limitez-vous à `sleep INTEGER` et évitez de chaîner plusieurs arguments.
Cas d’utilisation principaux dans les scripts Bash
1. Délai séquentiel entre les commandes
L’application la plus simple — insérer une pause entre deux opérations où la deuxième commande ne doit pas commencer avant qu’une condition réelle ait eu le temps de se stabiliser :
“`bash
#!/bin/bash
echo "Restarting nginx…"
systemctl restart nginx
sleep 3
systemctl status nginx
“`
La pause de 3 secondes ici tient compte de la séquence de démarrage asynchrone du gestionnaire de services. Sans elle, `status` peut signaler un état obsolète capturé avant que le processus ne soit complètement initialisé.
2. Boucle de sondage avec backoff exponentiel
Une boucle de nouvelle tentative à intervalle fixe naïve gaspille des ressources et peut amplifier la charge sur un service en difficulté. Le modèle correct est le backoff exponentiel avec gigue :
“`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
“`
Cela double le temps d’attente à chaque échec : 2s, 4s, 8s, 16s, 32s, 64s. L’attente maximale totale avant d’abandonner est de 126 secondes. Ce modèle est standard dans les scripts de déploiement en production, les vérifications de santé et les pipelines CI/CD.
3. Appels API à débit limité
Lors d’interactions avec des API qui appliquent des quotas de requêtes, `sleep` impose l’intervalle requis entre les requêtes :
“`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. Exécution de tâches en arrière-plan temporisées
L’exécution d’une commande différée sans bloquer la session shell actuelle nécessite de combiner `sleep` avec la mise en arrière-plan d’un sous-shell :
“`bash
Trigger a cache flush 60 seconds after deployment completes
( sleep 60 && redis-cli FLUSHDB ) &
echo "Cache flush scheduled. PID: $!"
“`
La variable `$!` capture le PID du sous-shell en arrière-plan, que vous pouvez ensuite utiliser avec `wait` ou `kill` si la tâche doit être annulée.
5. Boucle de surveillance et de supervision des processus
“`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
“`
Ce modèle est utilisé dans la supervision légère des processus lorsqu’un démon superviseur complet (systemd, supervisord, s6) est indisponible ou inapproprié — courant dans les environnements conteneurisés ou les instances VPS Hosting minimales.
6. Minuterie de compte à rebours avec retour utilisateur
Pour les scripts interactifs où l’opérateur a besoin de visibilité sur le temps d’attente restant :
“`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"` écrase la ligne actuelle plutôt que d’ajouter de nouvelles lignes, produisant un compte à rebours propre dans le terminal.
`sleep` vs. mécanismes de temporisation alternatifs
| Mécanisme | Granularité | Bloque le shell | Heure absolue | Cas d’utilisation |
|---|
| —————– | —————– | ————– | ————— | ———————————————– |
|---|
| `sleep` | Sous-seconde (GNU) | Oui (sauf `&`) | Non | Délais relatifs dans les scripts |
|---|
| `cron` | 1 minute | Non | Oui | Tâches planifiées récurrentes |
|---|
| `at` | 1 minute | Non | Oui | Exécution future ponctuelle |
|---|
| `systemd timer` | 1 seconde | Non | Oui | Tâches persistantes, journalisées et avec gestion des dépendances |
|---|
| `usleep` (C) | Microseconde | Oui | Non | Précision au niveau noyau/C (non natif Bash) |
|---|
| `read -t` | Sous-seconde | Oui | Non | Délai d’attente avec saisie utilisateur optionnelle |
|---|
Quand utiliser `read -t` plutôt que `sleep` : Si votre script doit se mettre en pause tout en permettant à un utilisateur d’interrompre ou de répondre pendant l’attente, `read -t SECONDS` est la primitive appropriée. Elle retourne le code de sortie 1 en cas d’expiration et 0 si l’utilisateur appuie sur Entrée, vous offrant une logique conditionnelle sans processus séparé.
“`bash
echo "Press Enter to skip the 10-second wait, or wait for automatic continuation."
read -t 10 -r || true
echo "Continuing…"
“`
Précision, virgule flottante et comportement selon la plateforme
GNU `sleep` accepte les fractions décimales, ce qui est important dans les scripts qui pilotent des animations, limitent le débit de consultation des journaux ou simulent des flux de données en temps réel :
“`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 durée réelle du sleep est un minimum, pas une garantie. L’ordonnanceur du noyau peut réveiller le processus légèrement en retard selon la charge système et la résolution du minuteur (`CONFIG_HZ`). Sur un Serveur Dédié fortement chargé exécutant des dizaines de processus simultanés, un `sleep 0.1` peut en réalité se mettre en pause pendant 0,11 à 0,15 secondes. Pour les scripts où cette dérive est inacceptable, utilisez une référence d’horloge monotone :
“`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
“`
Cette boucle compensant la dérive maintient un intervalle cohérent quelle que soit la durée de `do_work`.
Gestion des signaux et interruption de `sleep`
Un processus `sleep` en cours d’exécution répond aux signaux. L’envoi de `SIGALRM` au processus sleep le réveille immédiatement. Plus concrètement, appuyer sur `Ctrl+C` envoie `SIGINT` à l’ensemble du groupe de processus, terminant à la fois le script et tout `sleep` au premier plan.
Pour qu’un script gère proprement une interruption pendant 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."
“`
En mettant `sleep` en arrière-plan et en utilisant `wait`, le `trap` se déclenche immédiatement sur `SIGINT` plutôt que d’être différé jusqu’à la fin du sleep. C’est le modèle correct pour les scripts d’automatisation à longue durée d’exécution sur des serveurs de production.
Pièges pratiques et cas limites
Piège 1 : Utiliser `sleep` dans des boucles serrées sans condition de terminaison. Une boucle `while true; do sleep 1; done` sans chemin de sortie s’exécutera indéfiniment, consommant un emplacement de processus et s’accumulant dans la sortie `ps`. Définissez toujours un nombre maximum d’itérations ou une condition sentinelle.
Piège 2 : Supposer que `sleep` est synchrone avec les sous-shells. Lorsque vous créez un sous-shell avec `&`, le script parent n’attend pas que le `sleep` du sous-shell se termine à moins que vous n’appeliez explicitement `wait`. Cela provoque des conditions de course dans les scripts de déploiement parallèle.
Piège 3 : Coder en dur des délais pour la disponibilité des services. Utiliser `sleep 5` après le démarrage d’un service est fragile. Le service peut être prêt en 1 seconde ou prendre 30 secondes sous charge. L’alternative robuste est un sondage de disponibilité :
“`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."
“`
Piège 4 : Sleep à virgule flottante sur les systèmes BusyBox. Les conteneurs Alpine Linux utilisent le `sleep` de BusyBox, qui ne prend pas en charge les décimales. Tenter `sleep 0.5` générera une erreur. Validez votre environnement avant de déployer des scripts qui reposent sur une précision inférieure à la seconde.
Intégration de `sleep` dans les flux de travail automatisés de serveurs
Sur un VPS avec cPanel géré, les scripts de maintenance automatisés combinent fréquemment `sleep` avec cron pour implémenter une planification inférieure à la minute. Puisque la résolution minimale de cron est d’une minute, vous pouvez obtenir des intervalles de 15 secondes comme ceci :
“`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
“`
Cette technique est largement utilisée pour les processeurs de files d’attente, les vérifications de santé et les collecteurs de métriques sur une infrastructure partagée où l’installation d’un planificateur de tâches dédié n’est pas autorisée.
Pour les scripts de renouvellement de certificats SSL, `sleep` fournit le délai entre les tentatives lorsque la propagation du défi ACME nécessite l’expiration du TTL DNS avant que l’AC puisse vérifier la propriété. Si vous gérez des certificats sur votre propre infrastructure, les Certificats SSL avec des pipelines de renouvellement automatisé bénéficient d’intervalles de nouvelle tentative précisément ajustés.
De même, les scripts de vérification de propagation de domaine — utiles après la mise à jour des enregistrements via l’Enregistrement de domaine — utilisent des boucles `sleep` pour interroger les résolveurs DNS à des intervalles alignés sur les valeurs TTL attendues.
Matrice de décision : choisir la bonne stratégie de délai
| Scénario | Approche recommandée |
|---|
| ———————————————– | ————————————————— |
|---|
| Pause fixe entre deux commandes séquentielles | `sleep N` |
|---|
| Nouvelle tentative jusqu’au succès, éviter l’effet de troupeau | Backoff exponentiel avec `sleep` |
|---|
| Tâche récurrente toutes les N minutes | `cron` (pas `sleep`) |
|---|
| Tâche récurrente inférieure à la minute | `cron` + astuce de décalage `sleep` |
|---|
| Délai sans bloquer le terminal | `( sleep N && command ) &` |
|---|
| Pause avec possibilité d’interruption utilisateur | `sleep N &` + `wait $!` + `trap` |
|---|
| Vérification de disponibilité du service | Boucle de sondage port/santé avec `sleep 1` par tentative |
|---|
| Intervalle haute précision (compensation de dérive) | Référence d’horloge monotone avec `sleep` calculé |
|---|
| Délai sous-seconde sur Alpine/BusyBox | À éviter ; utiliser des secondes entières ou changer d’image de base |
|---|
Points techniques clés à retenir
- Utilisez toujours `sleep "$VARIABLE"` avec des guillemets doubles pour éviter les bugs de découpage de mots lorsque la variable contient une décimale.
- Préférez `sleep 1m 30s` à `sleep 90` pour la lisibilité dans les scripts de maintenance à longue durée d’exécution.
- Mettez `sleep` en arrière-plan avec `wait` et un `trap` chaque fois que votre script doit répondre aux signaux pendant la pause.
- N’utilisez jamais un `sleep` codé en dur comme substitut à une vérification de disponibilité appropriée — utilisez une boucle de sondage avec un délai d’expiration.
- Validez le comportement de `sleep` sur le système d’exploitation cible avant de déployer des scripts utilisant une syntaxe à virgule flottante ou à arguments multiples.
- Sur les serveurs de production, journalisez l’horodatage avant et après les appels `sleep` longs pour détecter la dérive de l’ordonnanceur lors des analyses post-incident.
- Lors de la création d’automatisations sur des Panneaux de contrôle VPS, vérifiez si le planificateur de tâches du panneau fournit déjà un contrôle d’intervalle avant d’ajouter manuellement une logique `sleep`.
FAQ
`sleep` consomme-t-il du CPU pendant l’attente ?
Non. `sleep` appelle `nanosleep()` (ou équivalent) au niveau du noyau, plaçant le processus dans un état de sleep interruptible (`S` dans la sortie `ps`). Il ne consomme aucun cycle CPU pendant l’attente — seulement une petite quantité de mémoire pour l’entrée du processus dans la table des processus.
Quelle est la valeur maximale acceptée par `sleep` ?
Sur GNU/Linux, `sleep` accepte des valeurs jusqu’aux limites d’un nombre à virgule flottante `double`, ce qui est effectivement illimité à des fins pratiques. `sleep 1d` (86400 secondes) est courant ; `sleep 365d` est valide. La limite pratique est la durée de fonctionnement du système.
Pourquoi `sleep 0.5` échoue-t-il sur mon conteneur Docker ?
Alpine Linux utilise BusyBox, dont l’implémentation de `sleep` n’accepte que des secondes entières. Passez à une image de base Debian ou Ubuntu, ou installez GNU coreutils (`apk add coreutils`) pour activer la prise en charge des décimales.
Puis-je annuler un processus `sleep` mis en arrière-plan ?
Oui. Capturez son PID avec `SLEEP_PID=$!` immédiatement après l’avoir mis en arrière-plan, puis utilisez `kill "$SLEEP_PID"` pour le terminer. Si vous avez utilisé `( sleep N && command ) &`, tuer le PID du sous-shell empêchera également l’exécution de la commande suivante.
Est-il sûr d’utiliser `sleep` dans le script `ExecStart` d’une unité de service `systemd` ?
Oui, mais avec des mises en garde. Si l’unité de service a `TimeoutStartSec` défini, un long `sleep` pendant le démarrage amènera systemd à tuer le service comme un démarrage échoué. Pour les délais post-démarrage, utilisez `ExecStartPost` avec un sondage de disponibilité, ou configurez `Type=forking` avec une gestion appropriée des fichiers PID plutôt que de compter sur `sleep` pour différer l’initialisation.
