Cron et automatisation#
L’automatisation des tâches récurrentes est l’un des usages les plus précieux de l’administration système. Sauvegardes nocturnes, rapports hebdomadaires, nettoyage de fichiers temporaires, envoi de notifications, synchronisation de bases de données — ces tâches seraient fastidieuses à exécuter manuellement et cruciales à ne pas oublier. Ce chapitre présente les deux mécanismes principaux de planification sous Linux : cron, le planificateur historique, et les timers systemd, son successeur moderne.
Architecture de cron#
cron est un démon Unix qui s’exécute en arrière-plan et surveille en permanence une base de données de tâches planifiées. Son architecture repose sur plusieurs composants distincts.
```{prf:definition} Le démon crond
:label: definition-18-01
crond (ou cron selon les distributions) est le processus démon qui tourne en permanence en arrière-plan. Chaque minute, il examine les tables de planification et lance les commandes dont l’heure d’exécution est atteinte. Il est généralement démarré au boot via le système d’init (SysV init, Upstart ou systemd).
### Les différentes tables de planification
`cron` lit les tâches planifiées depuis plusieurs emplacements :
**Les crontabs utilisateurs** : chaque utilisateur du système peut avoir sa propre crontab, gérée via `crontab -e`. Ces fichiers sont stockés dans `/var/spool/cron/crontabs/` (Debian/Ubuntu) ou `/var/spool/cron/` (Red Hat/CentOS). Les tâches s'exécutent avec les permissions de l'utilisateur propriétaire.
**La crontab système** : le fichier `/etc/crontab` est une crontab système qui contient un champ supplémentaire — le nom d'utilisateur sous lequel la commande doit s'exécuter.
**Le répertoire `/etc/cron.d/`** : les applications et paquets installent leurs planifications dans ce répertoire sous forme de fichiers distincts. Chaque fichier suit le même format que `/etc/crontab` (avec le champ utilisateur).
**Les répertoires périodiques** : `/etc/cron.hourly/`, `/etc/cron.daily/`, `/etc/cron.weekly/` et `/etc/cron.monthly/` contiennent des scripts shell qui seront exécutés automatiquement à la fréquence indiquée par leur répertoire. Il suffit de déposer un script exécutable dans ces répertoires sans écrire de syntaxe crontab.
```bash
# Structure des répertoires cron
ls -la /etc/cron.daily/
# logrotate apt-compat dpkg man-db ...
Syntaxe crontab#
La syntaxe d’une entrée crontab est constituée de cinq champs de planification suivis de la commande à exécuter.
Définition 62 (Format d’une entrée crontab)
Une entrée crontab standard a la forme :
minute heure jour-du-mois mois jour-de-la-semaine commande
Les cinq champs de planification acceptent les valeurs suivantes :
| Champ | Valeur | Plage |
|:------|:-------|:------|
| minute | 0–59 | — |
| heure | 0–23 | — |
| jour-du-mois | 1–31 | — |
| mois | 1–12 ou jan–dec | — |
| jour-de-la-semaine | 0–7 (0 et 7 = dimanche) ou sun–sat | — |
Opérateurs de planification#
Exemple 31 (Opérateurs dans les champs crontab)
Opérateur |
Signification |
Exemple |
|---|---|---|
|
N’importe quelle valeur |
|
|
Liste de valeurs |
|
|
Plage de valeurs |
|
|
Pas (every) |
|
|
Dernier (certains crons) |
|
|
Au démarrage |
|
|
Toutes les heures |
équivalent |
|
Tous les jours |
équivalent |
|
Toutes les semaines |
équivalent |
|
Tous les mois |
équivalent |
|
Tous les ans |
équivalent |
# Exemples commentés de crontab
# Chaque minute (pour tests — à ne pas laisser en production)
* * * * * /usr/local/bin/mon_script.sh
# Tous les jours à 2h30 du matin
30 2 * * * /usr/local/bin/sauvegarde.sh
# Tous les lundis à 8h00
0 8 * * 1 /usr/local/bin/rapport_hebdo.sh
# Le 1er de chaque mois à minuit
0 0 1 * * /usr/local/bin/archivage_mensuel.sh
# Toutes les 15 minutes entre 9h et 18h, du lundi au vendredi
*/15 9-18 * * 1-5 /usr/local/bin/sync_donnees.sh
# Le 15 et le dernier jour du mois à 3h
0 3 15,L * * /usr/local/bin/facturation.sh
# Au démarrage du système
@reboot /usr/local/bin/initialiser_cache.sh
# Tous les jours à minuit (alias)
@daily /usr/local/bin/nettoyage.sh
Gestion des crontabs#
Définition 63 (Commandes de gestion des crontabs)
crontab -e: ouvre la crontab de l’utilisateur courant dans l’éditeur défini parEDITORouVISUAL.crontab -l: liste le contenu de la crontab courante.crontab -r: supprime la crontab courante (attention : irréversible sans sauvegarde).crontab -u utilisateur -e: modifie la crontab d’un autre utilisateur (requiert les droits root).crontab fichier.crontab: remplace la crontab courante par le contenu du fichier.
# Sauvegarder la crontab avant de la modifier
crontab -l > ~/sauvegarde_crontab_$(date +%Y%m%d).txt
# Modifier la crontab
crontab -e
# Restaurer depuis une sauvegarde
crontab ~/sauvegarde_crontab_20240315.txt
# Vérifier la crontab d'un autre utilisateur (en root)
crontab -u www-data -l
Variables dans crontab#
La crontab peut définir des variables d’environnement qui s’appliquent à toutes les commandes de la crontab.
Remarque 49
Variables importantes dans une crontab :
MAILTO: adresse email à laquelle envoyer la sortie des commandes.MAILTO=""désactive les emails (très utile pour éviter le spam si les commandes produisent une sortie normale).PATH: chemin de recherche des commandes. C’est l’une des sources de problèmes les plus fréquentes : lePATHde cron est très limité (typiquement/usr/bin:/bin), et les scripts qui fonctionnent en ligne de commande peuvent échouer dans cron car les commandes ne sont pas trouvées.SHELL: shell utilisé pour exécuter les commandes (défaut :/bin/sh, pas Bash !).HOME: répertoire personnel (défaut : le$HOMEde l’utilisateur depuis/etc/passwd).
# En-tête recommandé pour une crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
HOME=/home/utilisateur
# Tâches
30 2 * * * /usr/local/bin/sauvegarde.sh
Pièges courants de cron#
cron est réputé pour ses pièges, qui peuvent rendre le débogage difficile si on ne les connaît pas.
Exemple 32 (Les pièges classiques de cron)
Piège 1 : le PATH réduit. La solution la plus sûre est d’utiliser des chemins absolus pour toutes les commandes dans les scripts cron, ou de définir explicitement PATH en tête de crontab.
# Fragile : curl peut ne pas être dans le PATH de cron
0 6 * * * curl https://api.exemple.fr/rapport
# Robuste : chemin absolu
0 6 * * * /usr/bin/curl https://api.exemple.fr/rapport
Piège 2 : pas de terminal (tty). Les commandes qui nécessitent une interaction avec un terminal (demande de mot de passe, affichage graphique, etc.) échouent silencieusement dans cron.
Piège 3 : pas de variables d’environnement du shell. Les variables définies dans ~/.bashrc, ~/.bash_profile ou ~/.profile ne sont pas chargées par cron. Les scripts qui en dépendent (aliases, fonctions, variables NVM_DIR, JAVA_HOME, etc.) doivent sourcer explicitement ces fichiers ou définir leurs propres variables.
# Sourcer le profil dans le script cron
0 2 * * * source /home/alice/.bashrc && /home/alice/bin/mon_script.sh
# Ou mieux : définir toutes les dépendances dans le script lui-même
Piège 4 : le caractère % est interprété par cron. Dans une crontab, le caractère % (utilisé par exemple dans date +%Y-%m-%d) est interprété comme un saut de ligne. Il faut l’échapper avec \%.
# FAUX : le % dans date est interprété
0 2 * * * /usr/bin/touch /tmp/test-$(date +%Y-%m-%d)
# CORRECT : échapper les %
0 2 * * * /usr/bin/touch /tmp/test-$(/usr/bin/date +\%Y-\%m-\%d)
# Plus propre : mettre la logique dans un script
Piège 5 : les répertoires de travail implicites. Le répertoire courant dans cron est généralement le $HOME de l’utilisateur. Un script qui utilise des chemins relatifs peut se comporter différemment. La bonne pratique est de définir explicitement le répertoire de travail dans le script avec cd /chemin/absolu || exit 1.
## `systemd` timers : l'alternative moderne
Depuis l'adoption généralisée de `systemd` comme système d'init sur les distributions Linux majeures, les **timers systemd** offrent une alternative puissante et bien intégrée à `cron`.
```{prf:definition} Timers systemd
:label: definition-18-04
Un timer systemd est une **unité** (fichier `.timer`) qui déclenche l'exécution d'une **unité de service** (fichier `.service`) associée selon un calendrier défini. Les deux fichiers ont le même nom de base (ex. `sauvegarde.timer` déclenche `sauvegarde.service`). Les timers sont gérés via `systemctl` et leurs journaux sont disponibles dans `journald`.
Exemple complet : créer un timer systemd#
Étape 1 : écrire le fichier service (/etc/systemd/system/sauvegarde.service)
[Unit]
Description=Sauvegarde quotidienne de la base de données
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=oneshot
User=backup
Group=backup
ExecStart=/usr/local/bin/sauvegarde_bdd.sh
StandardOutput=journal
StandardError=journal
# Timeout de 1 heure maximum
TimeoutStartSec=3600
Étape 2 : écrire le fichier timer (/etc/systemd/system/sauvegarde.timer)
[Unit]
Description=Planification de la sauvegarde quotidienne
Requires=sauvegarde.service
[Timer]
# Tous les jours à 2h30
OnCalendar=*-*-* 02:30:00
# Si la machine était éteinte à l'heure prévue, rattraper la tâche
Persistent=true
# Décalage aléatoire jusqu'à 30 minutes pour éviter les pics de charge
RandomizedDelaySec=30min
[Install]
WantedBy=timers.target
Étape 3 : activer et démarrer le timer
# Recharger systemd après avoir créé les fichiers
systemctl daemon-reload
# Activer le timer au démarrage
systemctl enable sauvegarde.timer
# Démarrer le timer maintenant
systemctl start sauvegarde.timer
# Vérifier le statut
systemctl status sauvegarde.timer
# Lister tous les timers actifs
systemctl list-timers
# Consulter les journaux du service
journalctl -u sauvegarde.service -f
journalctl -u sauvegarde.service --since "1 day ago"
La directive OnCalendar#
OnCalendar accepte une syntaxe riche pour décrire des planifications complexes :
```{prf:example} Syntaxe OnCalendar
:label: example-18-03
# Format : DayOfWeek YYYY-MM-DD HH:MM:SS
# Les composants peuvent être des listes, des ranges ou des jokers
OnCalendar=daily # Tous les jours à minuit
OnCalendar=weekly # Tous les lundis à minuit
OnCalendar=monthly # Le 1er de chaque mois à minuit
OnCalendar=hourly # Toutes les heures
OnCalendar=*-*-* 02:30:00 # Tous les jours à 2h30
OnCalendar=Mon *-*-* 08:00:00 # Tous les lundis à 8h
OnCalendar=Mon..Fri *-*-* 09:00 # Du lundi au vendredi à 9h
OnCalendar=*-*-01 00:00:00 # Le 1er de chaque mois
OnCalendar=*-01,07-01 00:00:00 # Le 1er janvier et le 1er juillet
OnCalendar=*:0/15 # Toutes les 15 minutes
OnCalendar=*:00,15,30,45 # Même chose, explicite
# Vérifier la prochaine occurrence d'une expression OnCalendar
systemd-analyze calendar "*-*-* 02:30:00"
Autres directives de timing#
En plus de OnCalendar (timing absolu), les timers systemd offrent des timings relatifs :
[Timer]
# Démarrer 5 minutes après le boot
OnBootSec=5min
# Démarrer 10 minutes après l'activation du timer
OnActiveSec=10min
# Répéter toutes les heures après le dernier démarrage du service
OnUnitActiveSec=1h
# Répéter 30 minutes après la fin du service (succès ou échec)
OnUnitInactiveSec=30min
Avantages des timers systemd sur cron#
Remarque 50
Les timers systemd présentent plusieurs avantages décisifs par rapport à cron :
Journalisation intégrée. Toute la sortie du service (stdout et stderr) est capturée par
journaldet consultable avecjournalctl. Avec cron, la sortie doit être redirigée manuellement ou envoyée par email.Gestion des dépendances.
After=,Wants=,Requires=permettent d’exprimer que la tâche doit s’exécuter après que certains services soient démarrés (base de données, réseau, etc.).Rattrapage des tâches manquées. Avec
Persistent=true, si la machine était éteinte à l’heure prévue, la tâche sera exécutée au prochain démarrage.Délai aléatoire.
RandomizedDelaySecdisperse les exécutions dans le temps, ce qui évite les pics de charge sur un parc de machines.Isolation et sécurité. Les unités systemd peuvent définir des namespaces, limites de ressources, utilisateurs dédiés, systèmes de fichiers en lecture seule, etc.
Monitoring unifié.
systemctl status,systemctl list-timersetjournalctldonnent une vue cohérente de l’état de toutes les tâches planifiées.
at : tâches ponctuelles différées#
cron et les timers systemd sont conçus pour les tâches récurrentes. Pour une tâche à exécuter une seule fois dans le futur, at est l’outil approprié.
```{prf:definition} La commande at
:label: definition-18-05
at permet de planifier une tâche ponctuelle pour une exécution future. Il accepte une grande variété de spécifications temporelles en anglais : now + 1 hour, 3:30pm tomorrow, noon, midnight, Jan 15, etc. Les tâches sont gérées par le démon atd.
```bash
# Planifier une commande dans une heure
echo "/usr/local/bin/envoyer_rapport.sh" | at now + 1 hour
# Syntaxe interactive (terminer avec Ctrl+D)
at 23:30
> /usr/local/bin/sauvegarde.sh
> mail -s "Rapport" admin@exemple.fr < /tmp/rapport.txt
> ^D
# Planifier pour demain à 8h
at 8:00 tomorrow
# Planifier pour une date précise
at 14:30 March 21
# Lister les tâches en attente
atq
# ou
at -l
# Afficher le détail d'une tâche (numéro donné par atq)
at -c 42
# Supprimer une tâche
atrm 42
# ou
at -d 42
Remarque 51
at hérite du même environnement restreint que cron concernant le PATH. La sortie standard et stderr sont envoyées par email à l’utilisateur (si un MTA est configuré). Pour éviter cela, rediriger explicitement dans la tâche : ma_commande > /var/log/ma_tache.log 2>&1.
L’accès à at peut être contrôlé via les fichiers /etc/at.allow et /etc/at.deny : si at.allow existe, seuls les utilisateurs y figurant peuvent l’utiliser ; sinon, at.deny liste les utilisateurs qui n’y ont pas accès.
Journalisation des tâches planifiées#
La journalisation des tâches cron est un aspect souvent négligé qui peut rendre le débogage difficile.
Rediriger stdout et stderr dans cron#
# Tout capturer dans un fichier de log avec horodatage
30 2 * * * /usr/local/bin/sauvegarde.sh >> /var/log/sauvegarde.log 2>&1
# Créer un log daté pour chaque exécution
0 6 * * * /usr/local/bin/rapport.sh > "/var/log/rapport_$(date +\%Y\%m\%d).log" 2>&1
# Séparer stdout et stderr
*/5 * * * * /usr/local/bin/surveillance.sh \
>> /var/log/surveillance_out.log \
2>> /var/log/surveillance_err.log
# Supprimer toute sortie (si la tâche est silencieuse par convention)
@daily /usr/local/bin/nettoyage.sh > /dev/null 2>&1
logger : écrire dans le journal système#
La commande logger permet d’envoyer des messages vers le journal système (syslog / journald), ce qui centralise les logs de toutes les tâches dans un seul endroit.
```{prf:definition} La commande logger
:label: definition-18-06
logger envoie un message au démon syslog local. Les messages sont consultables via journalctl (systemd) ou dans /var/log/syslog. La commande accepte une priorité (-p), un tag (-t) et le message lui-même.
```bash
# Envoyer un message d'information
logger -t sauvegarde "Début de la sauvegarde quotidienne"
# Envoyer un message d'erreur
logger -t sauvegarde -p user.error "Échec de la sauvegarde : espace disque insuffisant"
# Utilisation dans un script cron
#!/usr/bin/env bash
set -euo pipefail
readonly TAG="sauvegarde-bdd"
logger -t "$TAG" "Démarrage de la sauvegarde"
if pg_dump -Fc ma_base > /var/backups/ma_base_$(date +%Y%m%d).dump; then
logger -t "$TAG" "Sauvegarde terminée avec succès"
else
logger -t "$TAG" -p user.error "Échec de la sauvegarde"
exit 1
fi
# Consulter les logs d'un tag spécifique
journalctl -t sauvegarde-bdd
journalctl -t sauvegarde-bdd --since "7 days ago"
# Dans le syslog traditionnel
grep "sauvegarde-bdd" /var/log/syslog
Rotation des logs avec logrotate#
Pour éviter que les fichiers de log ne grossissent indéfiniment, on utilise logrotate :
# /etc/logrotate.d/mes-scripts-cron
/var/log/sauvegarde.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 root adm
}
Résumé#
Ce chapitre a couvert les mécanismes de planification de tâches sous Linux :
cronest le planificateur historique, présent sur tous les systèmes Unix. Sa syntaxe à cinq champs (minute, heure, jour, mois, jour-semaine) est concise mais parfois contre-intuitive. Ses principaux pièges — PATH réduit, absence de variables d’environnement, interprétation du%— nécessitent une attention particulière.crontab -e,-let-rgèrent la crontab de l’utilisateur courant ;/etc/cron.d/et les répertoires périodiques permettent une installation système.Les timers systemd offrent une alternative moderne avec des avantages substantiels : journalisation automatique via
journald, gestion des dépendances, rattrapage des tâches manquées avecPersistent=true, isolation de sécurité et délais aléatoires avecRandomizedDelaySec.atcouvre le cas d’usage des tâches ponctuelles différées, à la différence de cron qui gère les récurrences.La journalisation — redirection vers des fichiers de log datés, utilisation de
loggervers syslog — est indispensable pour surveiller et déboguer les tâches planifiées.
Dans le chapitre suivant, nous explorons la frontière entre Bash et les autres langages de programmation, et en particulier la collaboration entre Bash et Python.