Retour au cours

infra / linux-bash

Cron et tâches planifiées avancées

Leçon 171 exercice

Explication

Certaines tâches doivent s'exécuter automatiquement, sans qu'un humain tape une commande : une sauvegarde à 3h du matin, un nettoyage de fichiers temporaires chaque nuit. Cron est le planificateur intégré à Linux qui déclenche des commandes à des moments précis, définis une fois pour toutes.

Ce que vous allez apprendre

  • Lire et écrire une expression cron à cinq champs sans se tromper
  • Comprendre pourquoi un script qui marche à la main peut échouer silencieusement sous cron
  • Rediriger systématiquement la sortie et les erreurs d'un job planifié vers un log
  • Empêcher deux exécutions d'un même job de se chevaucher avec flock
  • Savoir quand préférer un timer systemd à une entrée crontab classique

Dans quel contexte ?

Un administrateur système programme une sauvegarde automatique de la base de données PostgreSQL de production, tous les jours à 3h du matin. Le script fonctionne parfaitement quand il le lance à la main, mais échoue systématiquement quand cron le déclenche — sans aucun message d'erreur visible nulle part. C'est un cas d'école : cron ne connaît ni le PATH complet ni les variables d'environnement du terminal habituel.

Ensuite, il faut apprendre à lire sa syntaxe à cinq champs

Une ligne crontab suit toujours l'ordre : minute, heure, jour du mois, mois, jour de semaine, puis la commande.

ExpressionSignification
0 3 * * *Tous les jours à 3h00 précises
*/15 * * * *Toutes les 15 minutes
0 9 * * 1-5À 9h00, du lundi au vendredi
0 0 1 * *Le 1er de chaque mois à minuit
@rebootUne seule fois, au démarrage du système

Une fois cette lecture acquise, attention à une confusion fréquente : */15 * * * * ne veut pas dire "15h", mais "toutes les 15 minutes". Vérifie toujours une expression cron avant de la déployer, une étoile mal placée peut faire tourner un job toutes les minutes au lieu d'une fois par jour.

Il reste un problème : cron ne connaît presque rien de ton shell

Une tâche cron s'exécute dans un environnement minimal, sans le PATH complet ni les variables que tu utilises dans ton terminal. Un script qui fonctionne parfaitement à la main peut échouer silencieusement sous cron, simplement parce que python3 n'est pas trouvé.

Piège fréquent

Écrire 0 3 * * * python3 backup.py dans une crontab échoue souvent avec "command not found", car cron ne cherche pas dans les mêmes dossiers qu'un terminal interactif. Toujours écrire des chemins absolus (/usr/bin/python3 /home/deploy/backup.py) et déclarer explicitement le PATH en haut du fichier crontab si besoin.

Un deuxième piège, plus vicieux : les erreurs silencieuses

Par défaut, cron n'affiche nulle part les erreurs d'un job : elles disparaissent, sauf si tu les rediriges toi-même.

Bonne pratique

Termine toujours une ligne crontab par une redirection explicite : 0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 capture à la fois la sortie normale et les erreurs dans un fichier que tu peux relire ensuite, plutôt que de découvrir un échec des semaines plus tard.

Maintenant que tu sais planifier, voyons ce qui se passe si un job dure trop longtemps

Si une tâche programmée toutes les 5 minutes met occasionnellement 6 minutes à s'exécuter, deux instances peuvent tourner en même temps et se marcher dessus. flock -n /tmp/sync.lock ta_commande empêche ce chevauchement en garantissant qu'une seule copie tourne à la fois.

/etc/cron.d/ et /etc/cron.daily/ gèrent des tâches système sans passer par crontab -e. La leçon suivante va plus loin avec systemd, une alternative moderne à cron avec des logs centralisés.

Commandes & code

Cron et tâches planifiées avancées

bash
crontab -l              # liste les tâches cron de l'utilisateur courant
crontab -e                # édite (ouvre l'éditeur par défaut)
crontab -r                  # supprime TOUTES les tâches (attention)
sudo crontab -u deploy -l     # liste les tâches d'un autre utilisateur

# Format : minute heure jour_du_mois mois jour_de_semaine  commande
# *  *  *  *  *
# |  |  |  |  |
# |  |  |  |  └── jour de la semaine (0-7, 0 et 7 = dimanche)
# |  |  |  └───── mois (1-12)
# |  |  └──────── jour du mois (1-31)
# |  └─────────── heure (0-23)
# └────────────── minute (0-59)

0 3 * * *        /usr/local/bin/backup.sh              # tous les jours à 3h00
*/15 * * * *      curl -fsS https://exemple.com/health   # toutes les 15 minutes
0 9 * * 1-5         /usr/local/bin/rapport_quotidien.sh   # 9h00, du lundi au vendredi
0 0 1 * *             /usr/local/bin/purge_archives.sh      # le 1er de chaque mois à minuit
@reboot                  /usr/local/bin/init_service.sh        # au démarrage du système
@daily                     /usr/local/bin/backup.sh                # équivalent à "0 0 * * *"

# Bonnes pratiques indispensables pour cron
# 1. cron n'a PAS ton PATH complet : toujours utiliser des chemins absolus
0 3 * * * /usr/bin/python3 /home/deploy/scripts/backup.py

# 2. rediriger les logs, sinon les erreurs disparaissent silencieusement
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# 3. utiliser flock pour éviter qu'un job se chevauche avec la run précédente (job trop long)
*/5 * * * * /usr/bin/flock -n /tmp/sync.lock /usr/local/bin/sync.sh

# 4. définir explicitement les variables d'environnement nécessaires en haut du crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=alerting@technologik.dev

# /etc/cron.d/, /etc/cron.daily/, /etc/cron.hourly/ : tâches système (pas besoin de crontab -e)
cat /etc/cron.d/mon-app
# ned  0 4 * * *  /usr/local/bin/tache_systeme.sh

# systemd timers : alternative moderne à cron, avec logs via journalctl
sudo systemctl status my-backup.timer
sudo systemctl list-timers --all         # voir tous les timers et leur prochaine exécution
# Voir la leçon "systemd avancé" pour créer un timer complet avec .service + .timer

Résumé

  • Format cron : minute heure jour mois jour_semaine commande — toujours chemins absolus.
  • Rediriger stdout/stderr (>> log 2>&1) évite de perdre silencieusement les erreurs d'un job planifié.
  • flock protège contre le chevauchement de deux exécutions d'un même job trop long.

Exercices pratiques

1 disponible
1

Mission : réparer une sauvegarde nocturne qui échoue en silence

Objectif : Corriger un job cron cassé par un environnement minimal, puis le protéger contre les erreurs silencieuses et les chevauchements.

Contexte

Le script backup.py fonctionne parfaitement quand l'administrateur le lance à la main. Programmé sous cron à 3h du matin, il échoue systématiquement avec "command not found", sans qu'aucune erreur ne soit visible ailleurs.

Résoudre l’exercice →