Aller au contenu principal

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
danger

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érateurSignification
*toutes les valeurs (chaque minute, chaque heure...)
*/15toutes les 15 unités (*/15 sur le champ minute = toutes les 15 minutes)
1-5une plage de valeurs
1,15une liste de valeurs précises
ExpressionSignification
30 2 * * *tous les jours à 2h30
0 */4 * * *toutes les 4 heures, pile
0 9 * * 1-5à 9h00, du lundi au vendredi
@dailyraccourci pour 0 0 * * *
@rebootau démarrage du système
30 2 * * * /usr/local/bin/sauvegarde.sh /var/www
info

/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 :

  1. $PATH minimal : cron n'exécute pas votre shell de connexion habituel, $PATH y 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/tar plutôt que tar).
  2. Aucune variable d'environnement de session : les variables définies dans votre .bashrc ne sont pas chargées par cron.
  3. Répertoire courant = $HOME, pas le dossier depuis lequel vous lanciez le script à la main — évitez les chemins relatifs.
  4. 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 (ou journalctl -u cron selon la distribution).
  • Pour simuler l'environnement minimal de cron directement dans votre terminal : env -i /bin/bash --noprofile --norc ouvre un shell quasiment vide, révélateur des dépendances implicites de votre script.
attention

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
cronsystemd timers
Simplicitéune seule lignedeux fichiers à écrire
Logsà gérer soi-même (redirection)intégrés (journalctl)
Dépendances entre tâchesnon géréespossibles (After=, Requires=)
Rattrapage après extinctionnonoui (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


Que signifie l'expression cron */15 * * * * ?


Quel est le 5e champ d'une expression cron ?


Pourquoi faut-il écrire le chemin absolu du script dans une crontab ?


Que devient la sortie d'un script cron non redirigée ?


Quelle directive systemd timer rattrape une exécution manquée ?


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


Bonne pratique - Permissions restreintes pour un script d'administration

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


Bonne pratique - Toujours tester avant l'horaire définitif

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


Bonne pratique - Vérifier avant de fermer crontab -e

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

NotionRésumé
case et [[ ]]case "$var" in motif) ... ;; esac, tests avancés avec [[ expr ]]
Tableauxtab=(...), "${tab[@]}", ${#tab[@]}, toujours quoté dans un for
getoptswhile getopts "hvd:" opt; do case "$opt" in ... esac done puis shift $((OPTIND-1))
Traitement de textegrep/cut/sort/wc/find reliés par des tubes |
sed et awksed 's/.../.../g' pour remplacer, awk -F'...' '{ }' pour calculer et formater par colonnes
Gestion d'erreursset -euo pipefail, trap cleanup EXIT, mktemp, verrou d'exécution
Planificationcrontab (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.