Planifier ses scripts : cron et systemd timers
Objectifs de la séance
- Automatiser l'exécution d'un script sans intervention humaine
- Lire et écrire une expression cron
- Éviter les pièges classiques d'environnement d'un script lancé par cron
- Découvrir les timers systemd, une alternative moderne à cron
- Faire le bilan des 7 séances de Bash niveau 2
Notions théoriques
Le démon cron
cron est un programme qui tourne en permanence en arrière-plan et déclenche des commandes à des horaires précis. Chaque utilisateur dispose de sa propre table cron (« crontab »), contenant la liste de ses tâches planifiées.
crontab -e # éditer sa table cron
crontab -l # lister sa table cron
crontab -r supprime intégralement votre table cron, sans aucune confirmation. Avant toute manipulation un peu risquée, sauvegardez votre table actuelle : crontab -l > sauvegarde.cron.
La syntaxe d'une ligne crontab
Une ligne crontab comporte 5 champs de temps, suivis de la commande à exécuter :
minute heure jour_du_mois mois jour_de_semaine commande
0-59 0-23 1-31 1-12 0-7 (0 et 7 = dimanche)
| Opérateur | Signification |
|---|---|
* | toutes les valeurs (chaque minute, chaque heure...) |
*/15 | toutes les 15 unités (*/15 sur le champ minute = toutes les 15 minutes) |
1-5 | une plage de valeurs |
1,15 | une liste de valeurs précises |
| Expression | Signification |
|---|---|
30 2 * * * | tous les jours à 2h30 |
0 */4 * * * | toutes les 4 heures, pile |
0 9 * * 1-5 | à 9h00, du lundi au vendredi |
@daily | raccourci pour 0 0 * * * |
@reboot | au démarrage du système |
30 2 * * * /usr/local/bin/sauvegarde.sh /var/www
/etc/crontab et les fichiers de /etc/cron.d/ suivent une syntaxe légèrement différente : ils comportent un champ utilisateur supplémentaire entre les champs de temps et la commande, puisqu'ils ne sont pas liés à un utilisateur unique comme une crontab personnelle. Le dossier /etc/cron.daily/ contient, lui, de simples scripts exécutés une fois par jour, sans expression cron à écrire — anacron prend le relais sur ce dossier pour rattraper l'exécution sur une machine qui aurait été éteinte au moment prévu.
Les pièges classiques d'un script lancé par cron
Un script qui fonctionne parfaitement lancé à la main peut échouer silencieusement une fois planifié, pour quatre raisons récurrentes :
$PATHminimal : cron n'exécute pas votre shell de connexion habituel,$PATHy est très réduit. Utilisez toujours des chemins absolus, pour le script lui-même dans la crontab (/usr/local/bin/sauvegarde.sh) et pour les commandes qu'il appelle en interne (/usr/bin/tarplutôt quetar).- Aucune variable d'environnement de session : les variables définies dans votre
.bashrcne sont pas chargées par cron. - Répertoire courant =
$HOME, pas le dossier depuis lequel vous lanciez le script à la main — évitez les chemins relatifs. - Toute sortie non redirigée est envoyée par e-mail à l'utilisateur, si un serveur de mail local est configuré (et génère sinon une erreur silencieuse). Redirigez systématiquement :
30 2 * * * /usr/local/bin/sauvegarde.sh /var/www >> /var/log/sauvegarde.log 2>&1
Une ligne MAILTO="" en tête de crontab désactive complètement l'envoi de mail pour toutes les tâches qui suivent.
Tester une tâche planifiée
- Programmez d'abord la tâche à une fréquence rapprochée (
* * * * *, toutes les minutes), le temps de valider qu'elle fonctionne, avant de revenir à l'horaire définitif. - Vérifiez son exécution réelle avec
grep CRON /var/log/syslog(oujournalctl -u cronselon la distribution). - Pour simuler l'environnement minimal de cron directement dans votre terminal :
env -i /bin/bash --noprofile --norcouvre un shell quasiment vide, révélateur des dépendances implicites de votre script.
Si votre script est planifié trop fréquemment par rapport à sa durée d'exécution, plusieurs instances peuvent se chevaucher. Réutilisez le verrou d'exécution vu en séance 6 (mkdir ou flock -n) pour l'empêcher.
systemd timers : l'alternative moderne
Les systèmes utilisant systemd proposent une alternative à cron, sous la forme d'une paire de fichiers unités :
# /etc/systemd/system/sauvegarde.service
[Unit]
Description=Sauvegarde quotidienne
[Service]
ExecStart=/usr/local/bin/sauvegarde.sh /var/www
# /etc/systemd/system/sauvegarde.timer
[Unit]
Description=Planification de la sauvegarde
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
Persistent=true rattrape l'exécution manquée si la machine était éteinte à l'heure prévue — un avantage net sur cron, qui ignore simplement les créneaux manqués.
systemctl enable --now sauvegarde.timer
systemctl list-timers
journalctl -u sauvegarde.service
| cron | systemd timers | |
|---|---|---|
| Simplicité | une seule ligne | deux fichiers à écrire |
| Logs | à gérer soi-même (redirection) | intégrés (journalctl) |
| Dépendances entre tâches | non gérées | possibles (After=, Requires=) |
| Rattrapage après extinction | non | oui (Persistent=true) |
Exemple pratique
# Ligne crontab, sauvegarde quotidienne à 2h30
30 2 * * * /usr/local/bin/sauvegarde.sh -d /srv/backups /var/www >> /var/log/sauvegarde.log 2>&1
Équivalent avec systemd timers : les deux fichiers sauvegarde.service et sauvegarde.timer présentés dans les notions théoriques ci-dessus.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
sauvegarde.sh passe aujourd'hui en version « production », installée et planifiée sur un vrai serveur.
Étape 1 — Installer le script
chmod 700 évite que d'autres utilisateurs du serveur puissent lire ou modifier un script qui manipule potentiellement des données sensibles.
Étape 2 — Planifier une exécution de test
Une exécution toutes les minutes permet de valider en quelques instants que le script fonctionne dans l'environnement restreint de cron, plutôt que d'attendre le lendemain 2h30 pour découvrir un problème.
Étape 3 — Corriger le piège du PATH et revenir à l'horaire final
Après avoir enregistré votre crontab, relancez crontab -l pour vérifier que la ligne a bien été prise en compte telle que vous l'avez écrite.
Étape 4 (bonus) — Écrire les unités systemd équivalentes
📌 Une solution
Ce qu'il faut retenir
| Notion | Résumé |
|---|---|
| case et [[ ]] | case "$var" in motif) ... ;; esac, tests avancés avec [[ expr ]] |
| Tableaux | tab=(...), "${tab[@]}", ${#tab[@]}, toujours quoté dans un for |
| getopts | while getopts "hvd:" opt; do case "$opt" in ... esac done puis shift $((OPTIND-1)) |
| Traitement de texte | grep/cut/sort/wc/find reliés par des tubes | |
| sed et awk | sed 's/.../.../g' pour remplacer, awk -F'...' '{ }' pour calculer et formater par colonnes |
| Gestion d'erreurs | set -euo pipefail, trap cleanup EXIT, mktemp, verrou d'exécution |
| Planification | crontab (min heure jour mois jour_semaine commande), pièges de $PATH/environnement, systemd timers |
Aperçu de la prochaine séance
Vous savez maintenant écrire des scripts Bash complets, robustes et planifiés automatiquement — un vrai outil d'administration de bout en bout. Deux directions s'ouvrent à vous à partir d'ici : le cours Interfaces conviviales (50_InterfacesConviviales) vous apprendra à transformer un script comme sauvegarde.sh en une petite application console avec de vrais menus et boîtes de dialogue grâce à dialog et whiptail, tandis que PowerShell – niveau 1 (30_PowerShell_Niveau1) vous fera découvrir l'équivalent de tout ce que vous venez d'apprendre, mais côté administration Windows.