Développement Web

Automatiser ses scripts avec cron : tâches planifiées et journalisation

14 دقائق للقراءة
📍 Article principal de la série : Bash scripting : le guide complet pour automatiser sous Linux. Ce tutoriel clôt la série « Bash scripting ». Il assemble tout ce que vous avez construit.

Un script qu’il faut penser à lancer soi-même n’est qu’à moitié automatisé. La vraie automatisation, c’est quand la machine fait le travail toute seule, à heure fixe, même quand vous dormez ou que vous êtes chez un autre client. C’est le rôle de cron, le planificateur de tâches présent sur tous les systèmes Unix depuis des décennies. À la fin de ce tutoriel, votre rapport de trafic se générera tout seul chaque semaine, vos vieux journaux se nettoieront automatiquement, et vous saurez vérifier que tout s’est bien passé — sans lever le petit doigt.

Dans le fil rouge, Boubacar a tous ses outils. Il manque la dernière pièce : les faire tourner automatiquement. Il planifie rapport-trafic.sh chaque lundi matin, ajoute une tâche de ménage qui supprime les journaux de plus de 30 jours, et journalise tout pour pouvoir contrôler à distance que ses serveurs vont bien.

🎯 Ce que vous allez apprendre

  • Lire et écrire une table cron (crontab -e, -l) et décoder ses cinq champs ;
  • Planifier une tâche (quotidienne, hebdomadaire, toutes les 15 minutes) avec la bonne syntaxe ;
  • Éviter les pièges classiques de cron : PATH réduit, chemins relatifs, % non échappé ;
  • Journaliser proprement la sortie et empêcher deux exécutions de se chevaucher avec flock.

🛠️ Ce que vous allez construire

Une tâche planifiée complète : un script rapport-hebdo.sh qui produit le rapport dans un fichier daté et nettoie les anciens journaux, plus l’entrée cron qui le déclenche chaque semaine, avec journalisation et verrou anti-chevauchement. Votre boîte à outils devient autonome.

Prérequis

  • Avoir suivi toute la série, en particulier grep, sed et awk (le script rapport-trafic.sh).
  • Test express : si vous savez rendre un script exécutable et le lancer avec un chemin absolu, vous êtes prêt.
  • Un accès à une machine Linux (un VPS est idéal). ⏱️ ~35 minutes.

Étape 1 — Comprendre les cinq champs de cron

Cron lit une table où chaque ligne décrit quand lancer quoi. Le « quand » tient en cinq champs, toujours dans le même ordre : minute, heure, jour du mois, mois, jour de la semaine. Le sixième élément, et tout ce qui suit, est la commande à exécuter. Une étoile * signifie « toutes les valeurs ».

# ┌───────── minute (0-59)
# │ ┌─────── heure (0-23)
# │ │ ┌───── jour du mois (1-31)
# │ │ │ ┌─── mois (1-12)
# │ │ │ │ ┌─ jour de la semaine (0-7, 0 et 7 = dimanche)
# │ │ │ │ │
# * * * * *  commande-à-lancer

Lisez de gauche à droite. 0 6 * * * veut dire « à la minute 0 de la 6ᵉ heure, tous les jours » — soit chaque jour à 6h00. 30 2 * * 1 veut dire « 2h30, le lundi » (jour 1 de la semaine). Ce système est rigide mais redoutablement clair une fois qu’on a le réflexe des cinq cases.

Étape 2 — Des exemples de planification courants

Trois symboles enrichissent les champs : la virgule (liste : 1,15), le tiret (intervalle : 9-17) et la barre oblique (pas : */15). Voici les planifications qu’on écrit le plus souvent, à garder en référence.

0 6 * * *      # tous les jours à 6h00
*/15 * * * *   # toutes les 15 minutes
0 8 * * 1      # chaque lundi à 8h00
0 2 1 * *      # le 1er de chaque mois à 2h00
0 9-17 * * 1-5 # toutes les heures de 9h à 17h, du lundi au vendredi

Le */15 mérite attention : il signifie « toutes les 15 unités » du champ minute, donc à 0, 15, 30 et 45. C’est la forme idéale pour une surveillance régulière. Cron propose aussi des raccourcis lisibles : @daily, @weekly, @monthly, @reboot (au démarrage de la machine). @weekly /chemin/script.sh remplace avantageusement 0 0 * * 0 quand l’heure exacte importe peu.

Étape 3 — Éditer sa table cron

Chaque utilisateur a sa propre table cron, qu’on édite avec crontab -e. La commande ouvre un éditeur ; on ajoute une ligne, on enregistre, et cron prend en compte le changement immédiatement. Deux autres options sont vitales : -l liste la table, et on évite soigneusement -r qui l’efface entièrement.

crontab -e      # éditer ma table cron
crontab -l      # afficher ma table cron
# crontab -r    # ⚠️ EFFACE toute la table — à ne pas confondre avec -e !

Le piège est réel : -r et -e sont voisins sur le clavier, et -r ne demande aucune confirmation. Avant toute manipulation, faites une sauvegarde : crontab -l > ma-crontab.txt. Vous pourrez la restaurer avec crontab ma-crontab.txt. Ce simple réflexe vous évitera un jour une mauvaise surprise.

Point d’étape — Ajoutez une tâche de test : * * * * * date >> ~/atelier/test-cron.log 2>&1. Au bout d’une minute ou deux, cat ~/atelier/test-cron.log doit montrer des horodatages. Si oui, cron fonctionne ; retirez ensuite cette ligne de test.

Étape 4 — Les trois pièges qui font échouer une tâche cron

« Mon script marche à la main mais pas dans cron » est la plainte universelle. Presque toujours, c’est l’un de ces trois pièges. Les connaître vous épargne des heures.

Premier piège : le PATH réduit. Cron ne charge pas votre environnement habituel. Le PATH y est minimal, et une commande comme mysqldump ou même awk dans un emplacement non standard devient introuvable. La parade : utiliser des chemins absolus, ou définir le PATH en tête de crontab.

# En haut de la crontab (avant les tâches) :
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash

Deuxième piège : les chemins relatifs. Cron lance la tâche depuis le répertoire personnel, pas depuis le dossier du script. Un script qui fait cd dossier ou ouvre config.txt en relatif échoue. Toujours écrire des chemins complets : /home/boubacar/atelier/rapport-trafic.sh, pas ./rapport-trafic.sh. Troisième piège : le caractère %, qui a une signification spéciale dans crontab (il est interprété comme un saut de ligne). Si votre commande en contient un — typiquement un format de date comme +%Y-%m-%d — il faut l’échapper en \%, ou mieux, l’enfermer dans un script plutôt que de l’écrire directement dans la crontab.

Étape 4 bis — Vérifier qu’une tâche s’est bien lancée

Avant même de regarder la sortie de votre script, il faut savoir si cron a seulement tenté de le lancer. Le démon cron tient son propre journal système, distinct de votre fichier de log. Le consulter répond à la question « cron a-t-il déclenché ma tâche à l’heure prévue ? », ce qui isole le problème : démarrage manqué d’un côté, erreur dans le script de l’autre.

# Selon la distribution :
grep CRON /var/log/syslog | tail        # Debian / Ubuntu
journalctl -u cron --since "today"       # systèmes avec systemd
journalctl -u crond --since "today"      # Fedora / CentOS (service crond)

Ces commandes montrent chaque déclenchement de cron avec son horodatage. Si votre tâche n’y apparaît pas à l’heure attendue, le problème est dans la planification (mauvais champ, syntaxe, table non enregistrée) ; si elle y apparaît mais que rien ne se passe, le problème est dans le script (chemin, PATH, permission) — et c’est là que votre journalisation, à l’étape suivante, prend tout son sens.

Étape 5 — Journaliser la sortie d’une tâche

Une tâche cron tourne sans personne pour regarder. Si elle échoue en silence, vous ne le saurez jamais — jusqu’à ce qu’un client signale un problème. La règle d’or : toujours rediriger la sortie vers un fichier journal. La syntaxe >> fichier 2>&1 ajoute (sans écraser) à la fois la sortie normale et les erreurs.

0 8 * * 1 /home/boubacar/atelier/rapport-hebdo.sh >> /home/boubacar/atelier/logs/cron.log 2>&1

Décomposons la redirection : >> ajoute à la fin du fichier (un simple > l’écraserait à chaque exécution), et 2>&1 redirige le canal d’erreur (2) vers le même endroit que la sortie normale (1). Ainsi tout — résultats comme messages d’erreur — atterrit dans cron.log, horodaté par votre script. Par défaut, cron tente d’envoyer la sortie par courriel à l’utilisateur ; rediriger vers un fichier est plus fiable et évite de remplir une boîte mail locale que personne ne lit.

Étape 6 — Assembler la tâche complète

On réunit tout dans rapport-hebdo.sh : il génère le rapport dans un fichier daté, journalise chaque étape, nettoie les vieux journaux, et se protège des exécutions simultanées avec flock. C’est le capstone de la série — il mobilise les fonctions, le mode strict, le traitement de texte et la planification.

#!/usr/bin/env bash
#
# rapport-hebdo.sh — génère le rapport de trafic et fait le ménage.
# Pensé pour être lancé par cron. Tous chemins ABSOLUS.
# Boîte à outils Atelier — tutoriel 6 (capstone).

set -euo pipefail

ATELIER="/home/boubacar/atelier"
LOG_ACCES="/var/log/nginx/access.log"
DOSSIER_RAPPORTS="$ATELIER/rapports"
JOURNAL="$ATELIER/logs/cron.log"

mkdir -p "$DOSSIER_RAPPORTS" "$ATELIER/logs"

journal() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$JOURNAL"; }

journal "=== Démarrage du rapport hebdomadaire ==="

# 1. Générer le rapport dans un fichier daté
date_jour=$(date '+%Y-%m-%d')
fichier="$DOSSIER_RAPPORTS/trafic-$date_jour.txt"
if "$ATELIER/rapport-trafic.sh" "$LOG_ACCES" > "$fichier" 2>> "$JOURNAL"; then
  journal "Rapport écrit : $fichier"
else
  journal "ÉCHEC de la génération du rapport (code $?)"
fi

# 2. Ménage : supprimer les rapports de plus de 90 jours
supprimes=$(find "$DOSSIER_RAPPORTS" -name 'trafic-*.txt' -mtime +90 -print -delete | wc -l)
journal "Ménage : $supprimes ancien(s) rapport(s) supprimé(s)."

journal "=== Fin ==="

Les nouveautés sont dans le ménage : find ... -mtime +90 -delete supprime les fichiers modifiés il y a plus de 90 jours (-mtime +90), et -print permet de les compter via wc -l. C’est la rotation des journaux du pauvre, parfaite pour un petit serveur. Tout passe par la fonction journal qui horodate chaque ligne dans cron.log — vous pourrez relire l’historique des exécutions à tout moment.

Reste à empêcher deux exécutions de se chevaucher (si une tâche déborde sur la suivante). flock pose un verrou : si le script tourne déjà, la nouvelle tentative est ignorée. On l’ajoute directement dans la crontab.

# crontab -e, puis :
PATH=/usr/local/bin:/usr/bin:/bin
0 8 * * 1 /usr/bin/flock -n /tmp/rapport-hebdo.lock /home/boubacar/atelier/rapport-hebdo.sh >> /home/boubacar/atelier/logs/cron.log 2>&1

flock -n /tmp/rapport-hebdo.lock prend un verrou exclusif ; l’option -n (non bloquant) fait que si le verrou est déjà pris, la commande renonce au lieu d’attendre. Chaque lundi à 8h, cron lance le script sous verrou, et toute la sortie va dans cron.log. Votre automatisation est complète et sûre.

Point d’étape final — Lancez rapport-hebdo.sh à la main une première fois pour vérifier qu’il produit un fichier dans rapports/ et des lignes dans logs/cron.log. Puis ajoutez l’entrée cron. La semaine suivante, le rapport sera là sans que vous y pensiez. Mission accomplie.

🐞 Pièges fréquents

Symptôme / erreur Cause probable Correctif
« Marche à la main, pas dans cron » PATH réduit ou chemins relatifs Chemins absolus partout ; définir PATH en tête de crontab
La commande s’arrête à un % % interprété par cron L’échapper en \% ou le mettre dans un script
Aucune trace de l’exécution Sortie non redirigée (partie en mail local) Ajouter >> fichier.log 2>&1
Deux exécutions se télescopent Tâche longue relancée avant la fin Encadrer avec flock -n /tmp/x.lock
Toute la crontab a disparu crontab -r tapé par erreur Restaurer depuis la sauvegarde crontab fichier.txt

🌍 Adaptation au contexte ouest-africain

L’automatisation par cron est une bénédiction quand on gère des serveurs à distance avec une connexion qui n’est pas toujours au rendez-vous : les tâches tournent côté serveur, indépendamment de votre liaison Internet. Un point d’attention propre à la région : les coupures électriques. Si le serveur (ou un VPS dont l’hôte redémarre) s’éteint à l’heure d’une tâche, cron classique ne la rattrape pas — la fenêtre est manquée. Deux parades : la directive @reboot pour relancer au démarrage, ou l’outil anacron, conçu pour les machines qui ne tournent pas 24h/24 et qui exécute les tâches manquées dès que possible. Pour un VPS chez un hébergeur sérieux, le problème ne se pose pas, mais c’est bon à savoir pour un serveur local en agence.

✅ Récapitulatif

Votre boîte à outils est désormais autonome. Vous savez lire et écrire une table cron, décoder ses cinq champs, planifier une tâche (quotidienne, hebdomadaire, par intervalle) et utiliser les raccourcis @daily/@weekly. Vous évitez les trois pièges mortels — PATH réduit, chemins relatifs, % non échappé — vous journalisez tout avec >> log 2>&1, et vous empêchez les chevauchements avec flock. rapport-hebdo.sh assemble tout l’apprentissage de la série en un capstone qui tourne tout seul. Bravo : vous savez écrire et automatiser de vrais outils Bash.

🧾 Aide-mémoire

Élément Rôle
crontab -e / -l Éditer / lister sa table cron
m h jm mois js cmd Les cinq champs de planification + commande
0 8 * * 1 Chaque lundi à 8h00
*/15 * * * * Toutes les 15 minutes
@daily / @reboot Raccourcis : chaque jour / au démarrage
>> log 2>&1 Journalise sortie + erreurs
find ... -mtime +90 -delete Supprime les fichiers vieux de 90+ jours
flock -n /tmp/x.lock cmd Empêche deux exécutions simultanées

💪 À vous de jouer

Ajoutez une seconde tâche cron qui, chaque jour à 7h, lance atelier.sh (tutoriel 4) sur le dossier d’un site et n’écrit dans le journal que si la vérification échoue — un mini-système d’alerte. Indice : un if ! commande; then journal ...; fi.

Voir une solution
# Dans un script surveille.sh lancé par cron :
if ! /home/boubacar/atelier/atelier.sh -d /var/www/boutique-aminata >/dev/null 2>&1; then
  echo "[$(date '+%F %T')] ALERTE : boutique-aminata en défaut !" >> "$JOURNAL"
fi
# crontab : 0 7 * * * /home/boubacar/atelier/surveille.sh

On ne journalise qu’en cas d’échec, ce qui garde le log propre et fait ressortir les vrais problèmes. Pour une supervision sérieuse (alertes par message, métriques), voir le tutoriel sysadmin ci-dessous.

Tutoriels frères

Pour aller plus loin

FAQ

Q : Où vont les courriels de cron si je ne redirige pas la sortie ?
R : Cron envoie la sortie à la boîte mail locale de l’utilisateur (via le système de mail local). Sur un serveur sans serveur mail configuré, ces messages s’accumulent ou se perdent. Rediriger vers un fichier journal est plus simple et plus fiable.

Q : cron ou systemd timers ?
R : cron est universel, simple, parfait pour la majorité des besoins. Les timers systemd (disponibles sur les distributions modernes) offrent plus : journalisation intégrée via journalctl, dépendances entre services, rattrapage des tâches manquées. Apprenez cron d’abord ; passez aux timers quand vous avez besoin de leurs fonctions avancées.

Q : Comment tester une tâche sans attendre l’heure prévue ?
R : Lancez le script à la main avec exactement la même commande que dans la crontab (chemin absolu compris), depuis un environnement minimal : env -i /bin/bash -c '/chemin/script.sh' reproduit l’environnement dépouillé de cron et révèle les problèmes de PATH.

Q : Ma tâche doit tourner toutes les minutes mais prend parfois plus d’une minute. Risque ?
R : Oui, les exécutions peuvent s’empiler et saturer la machine. C’est exactement le cas d’usage de flock -n : la nouvelle exécution renonce tant que la précédente n’a pas fini.

📚 Ressources et références

Mots-clés : cron, crontab, tâches planifiées, automatisation bash, planifier un script, flock, rotation de logs, journalisation cron, rapport-hebdo.

مشاركة