Chapitre 1513 minIntermédiaire
Tâches planifiées : crontab et timers systemd
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- lire et écrire une ligne de crontab ;
- choisir où ranger une tâche planifiée ;
- éviter les pièges classiques de cron ;
- écrire et activer un timer systemd.
4 exercices corrigés1 schéma
Planifier une tâche, c'est demander au système de lancer une commande ou un script automatiquement, à heure fixe ou à intervalle régulier : une sauvegarde chaque nuit, une purge chaque semaine, un rapport chaque lundi. Sous Linux, deux outils le font : cron, avec sa crontab et sa syntaxe en cinq champs, et les timers de systemd. Ce chapitre explique la syntaxe de la crontab avec des exemples, les pièges classiques, l'écriture d'un timer et le choix entre les deux.
La syntaxe de la crontab
Le démon cron lit chaque minute les tables de tâches et lance celles dont l'heure est venue. Une ligne de crontab compte cinq champs de date, puis la commande :
| Notation | Sens | Exemple |
|---|---|---|
* | Toutes les valeurs | * dans le champ heure : chaque heure |
, | Une liste | 1,15 dans le champ jour du mois : le 1er et le 15 |
- | Un intervalle | 8-18 dans le champ heure : de 8 h à 18 h |
/ | Un pas | */15 dans le champ minute : toutes les 15 minutes (0, 15, 30, 45) |
| Ligne | Exécution |
|---|---|
30 2 * * * … | Chaque jour à 2 h 30 |
0 * * * * … | Au début de chaque heure |
*/5 * * * * … | Toutes les 5 minutes |
0 19 * * 1-5 … | Du lundi au vendredi à 19 h |
15 3 * * 0 … | Chaque dimanche à 3 h 15 |
0 0 1 * * … | Le 1er de chaque mois à minuit |
0 0 1 1,4,7,10 * … | Le premier jour de chaque trimestre à minuit |
@reboot … | Une fois, au démarrage de la machine |
Les raccourcis @hourly, @daily, @weekly, @monthly existent aussi (@daily vaut 0 0 * * *).
Où écrire les tâches
| Emplacement | Pour qui | Format |
|---|---|---|
crontab -e | Les tâches d'un utilisateur (stockées dans /var/spool/cron/crontabs/<compte>) | Cinq champs + commande |
sudo crontab -e | Les tâches de root | Cinq champs + commande |
/etc/cron.d/<fichier> | Les tâches système, une par application | Cinq champs + compte + commande |
/etc/crontab | La table système principale | Cinq champs + compte + commande |
/etc/cron.daily/, cron.weekly/, cron.monthly/, cron.hourly/ | Des scripts lancés chaque jour, semaine, mois ou heure | Script exécutable, sans ligne de crontab |
crontab -l affiche la table, crontab -e l'ouvre dans l'éditeur et la vérifie à l'enregistrement. crontab -r la supprime sans confirmation : les touches e et r sont voisines.
Chez Sorbier, l'archivage nocturne de srv-journaux est une tâche système, dans son propre fichier :
# /etc/cron.d/archive-journaux
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
MAILTO=informatique@sorbier.example
# Archiver les journaux distants de plus de 30 jours, chaque nuit à 2 h 30
30 2 * * * root /usr/local/bin/archive-journaux >> /var/log/archive-journaux.log 2>&1
Sur Debian, les scripts des dossiers cron.daily et suivants sont lancés par run-parts depuis /etc/crontab : chaque jour à 6 h 25, chaque dimanche à 6 h 47, le 1er du mois à 6 h 52. Le paquet cron est présent sur une installation Debian standard ; s'il manque (image cloud, conteneur), sudo apt install cron, et systemctl status cron vérifie qu'il tourne. Son journal se lit avec journalctl -u cron.
Les pièges de cron
Une commande qui marche dans ton terminal et échoue dans cron, c'est presque toujours l'un de ces cinq pièges :
- Le
PATHréduit. Cron lance les commandes avec unPATHminimal (/usr/bin:/bin). Une commande de/usr/sbinou de/usr/local/binn'est pas trouvée. Écris les chemins complets, ou fixePATHen tête du fichier. - Pas de terminal ni de variables de session. Aucune variable de ton
.bashrc, aucun agent SSH, et le dossier courant est le dossier personnel du compte. Utilise des chemins absolus partout. - Le
%a un sens spécial dans une crontab (fin de commande, retour à la ligne) :date +%Fdoit s'écriredate +\%F. - La sortie perdue. Ce que la commande affiche est envoyé par courriel à
MAILTO, ou perdu si aucun agent de messagerie n'est configuré. Redirige vers un fichier (>> /var/log/… 2>&1) pour garder une trace des erreurs. - Les noms de scripts dans
cron.daily.run-partsignore les fichiers dont le nom contient un point : un scriptsauvegarde.shdéposé dans/etc/cron.daily/n'est jamais exécuté. Nomme-lesauvegarde, rends-le exécutable, et vérifie avecrun-parts --test /etc/cron.daily.
Les timers systemd
Un timer systemd est une unité .timer qui démarre une unité .service à une date donnée. Il faut deux fichiers, mais on gagne beaucoup : les journaux de chaque exécution dans journalctl, le rattrapage des exécutions manquées pendant un arrêt, un délai aléatoire pour ne pas lancer tout le parc à la même seconde, et toutes les protections d'une unité de service. Debian l'utilise déjà pour ses propres tâches (apt-daily.timer, logrotate.timer, fstrim.timer).
Le même archivage, en timer :
# /etc/systemd/system/archive-journaux.service
[Unit]
Description=Archivage des journaux distants de plus de 30 jours
[Service]
Type=oneshot
ExecStart=/usr/local/bin/archive-journaux
Nice=10
# /etc/systemd/system/archive-journaux.timer
[Unit]
Description=Archivage nocturne des journaux distants
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=10min
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now archive-journaux.timer # on active le timer, pas le service
systemctl list-timers archive-journaux.timer # prochaine et dernière exécution
sudo systemctl start archive-journaux.service # lancer une fois tout de suite, pour tester
journalctl -u archive-journaux.service # la sortie de chaque exécution
| Directive | Sens |
|---|---|
Type=oneshot | Le service fait son travail puis se termine |
OnCalendar=*-*-* 02:30:00 | Chaque jour à 2 h 30 (format jour-semaine année-mois-jour heure:minute:seconde) |
Persistent=true | Si la machine était éteinte à 2 h 30, la tâche est lancée au démarrage suivant |
RandomizedDelaySec=10min | Un délai aléatoire de 0 à 10 minutes |
OnBootSec=15min, OnUnitActiveSec=1h | Autre forme : 15 minutes après le démarrage, puis toutes les heures |
Quelques valeurs d'OnCalendar :
| Besoin | Crontab | OnCalendar |
|---|---|---|
| Chaque jour à 2 h 30 | 30 2 * * * | *-*-* 02:30:00 |
| Toutes les 5 minutes | */5 * * * * | *:0/5 |
| Du lundi au vendredi à 19 h | 0 19 * * 1-5 | Mon..Fri 19:00 |
| Chaque dimanche à 3 h 15 | 15 3 * * 0 | Sun 03:15 |
| Le 1er de chaque mois à minuit | 0 0 1 * * | *-*-01 00:00:00 (ou monthly) |
systemd-analyze calendar "Mon..Fri 19:00" vérifie une expression et affiche la prochaine échéance : un réflexe avant d'enregistrer un timer.
cron ou timer ?
| Critère | cron | Timer systemd |
|---|---|---|
| Mise en place | Une ligne | Deux fichiers |
| Journaux | À rediriger soi-même | Automatiques, dans journalctl |
| Tâche manquée pendant un arrêt | Perdue | Rattrapée avec Persistent=true |
| Échec visible | Par courriel, si configuré | systemctl --failed, supervisable |
| Protections (compte, droits, système en lecture seule) | Aucune | Toutes celles d'un service |
| Portabilité | Tous les Unix, y compris pfSense | Linux avec systemd |
Pour une tâche ponctuelle (redémarrer à 4 h cette nuit), l'outil est at (paquet at) : echo "systemctl reboot" | sudo at 04:00, atq pour la file, atrm pour annuler. Sans at, sudo systemd-run --on-calendar="2026-11-05 04:00" systemctl reboot crée un timer temporaire.
Le contenu des scripts eux-mêmes (variables, conditions, boucles, codes de retour) est l'objet du cours Scripts PowerShell et Bash.
Exercices
Exercice 1 sur 4 Lire des lignes de crontab Réussi À revoir
Quand s'exécutent ces tâches ?
*/15 8-18 * * 1-5 /usr/local/bin/verifier-site0 9-17/2 * * * /usr/local/bin/rapport0 6 1 * 1 /usr/local/bin/inventaire@reboot /usr/local/bin/prevenir-demarrage
Voir la réponseMasquer la réponse de l'exercice 1
- Du lundi au vendredi, toutes les 15 minutes de 8 h 00 à 18 h 45 (l'heure 18 est incluse, avec ses quatre quarts d'heure) : 44 exécutions par jour ouvré.
- Chaque jour à 9 h, 11 h, 13 h, 15 h et 17 h : l'intervalle 9-17 parcouru par pas de 2.
- À 6 h chaque lundi et chaque 1er du mois, puisque les deux champs de jour sont renseignés. Du 1er novembre au 1er décembre 2026 : le dimanche 1er novembre, les lundis 2, 9, 16, 23 et 30, puis le mardi 1er décembre.
- Une fois, à chaque démarrage de la machine.
Tu avais trouvé ?
Exercice 2 sur 4 Écrire des lignes de crontab Réussi À revoir
Écris la ligne de la crontab de root pour lancer /usr/local/bin/sauvegarde-config :
- chaque nuit à 1 h 45 ;
- du lundi au samedi à 22 h ;
- le premier jour de chaque trimestre à 5 h ;
- toutes les 10 minutes, mais seulement en semaine de 7 h à 19 h 50.
Voir la réponseMasquer la réponse de l'exercice 2
45 1 * * * /usr/local/bin/sauvegarde-config0 22 * * 1-6 /usr/local/bin/sauvegarde-config0 5 1 1,4,7,10 * /usr/local/bin/sauvegarde-config*/10 7-19 * * 1-5 /usr/local/bin/sauvegarde-config: de 7 h 00 à 19 h 50, toutes les 10 minutes.
Dans /etc/cron.d/, chaque ligne prendrait en plus le compte root entre la date et la commande.
Tu avais trouvé ?
Exercice 3 sur 4 Une tâche qui ne s'exécute pas Réussi À revoir
Moussa Diallo a placé un script nettoyage.sh dans /etc/cron.daily/, avec les droits -rw-r--r-- root root. Il contient la commande find /srv/journaux/tmp -mtime +7 -delete et fonctionne quand Moussa le lance avec sudo bash nettoyage.sh. Rien ne se passe pourtant chaque matin. Trouve les deux raisons.
Voir la réponseMasquer la réponse de l'exercice 3
- Le nom :
run-partsignore les fichiers dont le nom contient un point. Renommer en/etc/cron.daily/nettoyage. - Les droits : le script n'est pas exécutable (
rw-r--r--), etrun-partsne lance que les fichiers exécutables.sudo chmod 755 /etc/cron.daily/nettoyage, avec une première ligne#!/bin/bash.
Vérification : run-parts --test /etc/cron.daily doit lister le script. Moussa l'avait testé avec bash nettoyage.sh, qui ne demande ni le droit d'exécution ni un nom particulier : son test ne reproduisait pas les conditions de cron.
Tu avais trouvé ?
Exercice 4 sur 4 Passer à un timer systemd Réussi À revoir
Transforme la tâche 15 3 * * 0 root /usr/local/bin/purge-exports de srv-web en timer systemd, qui rattrape l'exécution si le serveur était éteint. Donne les deux fichiers et les commandes pour l'activer et le vérifier.
Voir la réponseMasquer la réponse de l'exercice 4
/etc/systemd/system/purge-exports.service :
[Unit]
Description=Purge hebdomadaire des exports
[Service]
Type=oneshot
ExecStart=/usr/local/bin/purge-exports
/etc/systemd/system/purge-exports.timer :
[Unit]
Description=Purge des exports chaque dimanche à 3 h 15
[Timer]
OnCalendar=Sun *-*-* 03:15:00
Persistent=true
[Install]
WantedBy=timers.target
Puis systemd-analyze calendar "Sun *-*-* 03:15:00" (prochaine échéance), sudo systemctl daemon-reload, sudo systemctl enable --now purge-exports.timer, systemctl list-timers purge-exports.timer, et un test immédiat avec sudo systemctl start purge-exports.service suivi de journalctl -u purge-exports.service. On supprime enfin la ligne de crontab, pour ne pas lancer la purge deux fois.
Tu avais trouvé ?