objectif
Garantir qu’une tâche ne s’exécute qu’une seule fois à la fois (cron, scripts de maintenance), avec échec rapide si déjà en cours.
code minimal
#!/usr/bin/env bash
set -Eeuo pipefail
lock="/tmp/mon_script.lock"
exec 9>"$lock"
flock -n 9 || { echo "déjà en cours"; exit 1; }
# section critique
echo "travail en cours..."
sleep 5
echo "terminé"
utilisation
# attente maximum 10s pour obtenir le verrou
lock="/tmp/backup.lock"
exec 9>"$lock"
flock -w 10 9 || { echo "verrou occupé"; exit 1; }
rsync -a --delete ./src/ ./dest/
# verrouillage autour d'une commande unique (syntaxe -c)
flock -n /tmp/cleanup.lock -c 'git clean -Xdf && git gc --prune=now'
# verrou nominatif par ressource (ex: base)
db="clients"
flock -n "/tmp/reindex.${db}.lock" -c "psql -d ${db} -c 'REINDEX DATABASE ${db};'"
# verrou par dossier (fallback portable quand flock indisponible)
lockd="/tmp/rapport.lock.d"
if mkdir "$lockd" 2>/dev/null; then
trap 'rmdir "$lockd"' EXIT INT TERM
./genere_rapport.sh
else
echo "déjà en cours"; exit 1
fi
variante(s) utile(s)
# inclure le PID dans le fichier pour le debug (flock se base sur le descripteur)
lock="/tmp/worker.lock"
printf '%s\n' "$$" > "$lock"
exec 9>"$lock"
flock -n 9 || { echo "en cours par PID $(cat "$lock" 2>/dev/null || echo "?")"; exit 1; }
# ... travail ...
# verrou exclusif sur un dossier de cache
flock -n /tmp/cache_sync.lock -c 'rsync -a --delete ./cache/ /mnt/cache/'
# tenter N fois avec backoff
lock="/tmp/task.lock"
exec 9>"$lock"
for i in 1 2 3; do
if flock -n 9; then break; fi
sleep $((i*i))
done
flock -n 9 || { echo "verrou indisponible"; exit 1; }
notes
- placez le fichier de verrouillage sur un filesystem local (évitez NFS).
- avec
flock, il est inutile de supprimer le fichier de lock; le verrou porte sur le descripteur. - la variante
mkdirfonctionne partout, mais assurez-vous de bien retirer le dossier dans letrap. - utilisez des noms de verrous distincts par ressource (ex:
/tmp/backup.<nom>.lock) pour éviter les collisions.