Aller au contenu principal
Questions et réponses sur l'hébergement web

Les tables cron de Linux expliquées, de la syntaxe à l'export MySQL nocturne

Une crontab linux associe un script ou une commande à cinq champs de temps : minute, heure, jour du mois, mois, jour de la semaine. Le service cron relit chaque table cron toutes les minutes et lance le job sous le compte de son user ; la sortie va dans un log si la ligne la redirige.

Éditer la crontab
crontab -e ouvre la table cron de l'utilisateur courant, crontab -l la liste.
Un example de ligne cron
30 2 * * * /home/site/bin/sauvegarde.sh lance le script chaque jour à 2 h 30, minute 30.
Garder un log
>> /home/site/logs/cron.log 2>&1 : chaque job cron de la crontab laisse sa trace.

Cron, crontab, tâche cron : trois mots pour un seul mécanisme

Cron désigne le démon, c'est-à-dire le service qui tourne en permanence sur la machine Linux et se réveille chaque minute pour consulter les tables. Crontab désigne à la fois la commande qui édite ces tables et le fichier lui-même (de l'anglais cron table). Une tâche cron, appelée cron job dans la documentation anglophone, correspond à une ligne de cette table : un moment, une commande.

Ce planificateur de tâches existe sur tous les systèmes de la famille Unix depuis les années 1970. Sur les distributions actuelles, deux implémentations dominent : le cron dérivé de Vixie cron, livré par Debian et Ubuntu, et cronie, livré par Red Hat, Fedora, Rocky Linux et Oracle Linux. Leur syntaxe crontab est identique pour l'essentiel ; les différences tiennent aux chemins des fichiers, au nom du service et à l'emplacement des journaux, résumés plus bas.

Le démon cron sert à exécuter automatiquement ce qui doit revenir à intervalle régulier : export des bases de données SQL chaque nuit, purge de fichiers temporaires chaque semaine, envoi d'un rapport chaque jour ouvré, appel d'un script PHP toutes les cinq minutes pour vider une file de courriels. Pour une action unique à une date donnée, la commande at convient mieux ; pour une machine souvent éteinte, anacron rattrape les tâches manquées, ce que cron ne fait pas.

Quelle est la syntaxe d'une ligne de crontab ?

Une ligne de crontab suit toujours le même ordre : minute, heure, jour du mois, mois, jour de la semaine, puis la commande. Les cinq champs de temps se séparent par des espaces ; tout ce qui suit le cinquième champ forme la commande, transmise telle quelle au shell /bin/sh.

ChampValeurs admisesExemple et sens
minute0 à 59*/5 : toutes les cinq minutes
heure0 à 232 : à 2 h du matin
jour du mois1 à 311,15 : le 1er et le 15
mois1 à 12, ou jan à dec6-8 : de juin à août
jour de la semaine0 à 7 (0 et 7 = dimanche), ou sun à sat1-5 : du lundi au vendredi

Quatre opérateurs suffisent à tout exprimer. L'étoile signifie « toutes les valeurs ». Le tiret donne un intervalle (1-5). La virgule donne une liste (0,30). La barre oblique donne un pas : */6 dans le champ des heures signifie toutes les six heures, 10-50/20 dans le champ des minutes donne 10, 30 et 50.

30 2 * * * /home/site/bin/sauvegarde.sh
0 */6 * * * /usr/bin/php /home/site/www/tache.php
15 7 * * 1-5 /home/site/bin/rapport.sh
*/5 * * * * /usr/bin/php /home/site/www/file-courriels.php

La première ligne lance la sauvegarde chaque jour à 2 h 30, la deuxième un script PHP toutes les six heures à la minute zéro, la troisième un rapport à 7 h 15 les jours ouvrés, la dernière une file de courriels toutes les cinq minutes.

Le cas du jour du mois et du jour de la semaine renseignés ensemble

Une ligne de crontab qui renseigne à la fois le jour du mois et le jour de la semaine se déclenche si l'un ou l'autre correspond, pas les deux à la fois. La ligne 0 9 13 * 5 part donc chaque vendredi et chaque 13 du mois, et non les seuls vendredis 13. Les pages de manuel crontab(5) décrivent ce comportement, source fréquente de lancements inattendus.

Les raccourcis @reboot, @daily et leurs voisins

Cron accepte aussi des chaînes spéciales à la place des cinq champs : @reboot (une fois au démarrage du démon), @hourly, @daily, @weekly, @monthly et @yearly. @daily équivaut à 0 0 * * *, soit minuit chaque jour. Ces raccourcis rendent la crontab plus lisible, mais lancent toutes les tâches « daily » d'un serveur à la même minute, ce qui charge la machine d'un coup.

Comment créer un fichier crontab pour son utilisateur ?

Pour créer un fichier crontab, la commande crontab -e suffit : elle ouvre un fichier temporaire dans l'éditeur défini par la variable EDITOR (nano ou vi le plus souvent), puis vérifie la syntaxe et installe la table à l'enregistrement. Une ligne mal formée provoque un message d'erreur et la proposition de rééditer, ce qui évite d'installer une table cassée.

Les autres options de la commande crontab couvrent le reste du cycle de vie :

  • crontab -l affiche la table de l'utilisateur courant ;
  • crontab fichier.txt remplace la table entière par le contenu d'un fichier, pratique pour versionner ses tâches ;
  • crontab -r supprime toute la table, sans confirmation sur la plupart des systèmes ;
  • crontab -u username -e, réservé à l'utilisateur root, édite la table d'un autre compte.

Le fichier installé ne se modifie jamais à la main. Debian et Ubuntu le rangent dans /var/spool/cron/crontabs/, Red Hat et ses dérivés dans /var/spool/cron/, un fichier par nom d'utilisateur. Passer par la commande crontab garantit que le démon cron recharge la table ; une édition directe peut rester ignorée.

Sur Debian et Ubuntu, une table vide s'ouvre avec un modèle commenté, en anglais, qui résume la syntaxe crontab ; les lignes précédées d'un # sont ignorées par cron :

  • la consigne de départ : Edit this file to introduce tasks to be run by cron, une task par ligne ;
  • les champs de time : minute (m), hour (h), day of month (dom), month (mon), and day of week (dow), ou * pour « any » ;
  • un example : 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/, pour run une archive every week, le lundi à 5 h ;
  • le renvoi aux manuels : For more information see the manual pages of crontab(5) and cron(8).

Ce modèle rappelle l'ordre des champs (m, h, dom, mon, dow) et donne un example concret : une archive des dossiers personnels chaque lundi à 5 h. Les lignes de commentaire peuvent rester en place ; seules les lignes actives comptent.

Une précaution simple consiste à sauvegarder la table avant toute modification importante : crontab -l > ~/crontab-sauvegarde.txt. Une restauration se fait ensuite par crontab ~/crontab-sauvegarde.txt.

Les fichiers cron du système, à côté des tables utilisateur

Les fichiers cron du système complètent les tables personnelles et se trouvent dans /etc. Ils servent aux paquets installés (rotation des logs, mises à jour de sécurité, nettoyage de /tmp) et à l'administrateur qui veut des tâches indépendantes d'un compte.

  • /etc/crontab : la table principale du système. Elle comporte un sixième champ, le nom de l'utilisateur sous lequel la commande s'exécute, placé entre le jour de la semaine et la commande.
  • /etc/cron.d/ : un fichier par paquet ou par application, au même format que /etc/crontab, avec le champ utilisateur.
  • /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/ et /etc/cron.monthly/ : des répertoires de scripts exécutables, lancés par run-parts une fois par heure, par jour, par semaine ou par mois.
# /etc/cron.d/sauvegarde-site
MAILTO=""
30 2 * * * site /home/site/bin/sauvegarde.sh >> /home/site/logs/cron.log 2>&1

Un piège propre à Debian et Ubuntu concerne run-parts : dans /etc/cron.daily/, un script nommé sauvegarde.sh ne s'exécute jamais, car run-parts ignore par défaut les noms qui contiennent un point. Le renommer sauvegarde, sans extension, règle la question. Le même problème touche /etc/cron.d/, dont les fichiers ne doivent pas porter d'extension.

Sur Debian et Ubuntu avec anacron installé, les répertoires daily, weekly et monthly passent par anacron, ce qui décale l'heure réelle d'exécution mais rattrape les jours où la machine était éteinte.

Debian, Ubuntu et Red Hat : ce qui change d'une distribution à l'autre

La syntaxe des tâches cron reste la même partout ; le nom du service, le dossier des tables et la place du log changent selon la distribution Linux. Le tableau rassemble ce qu'il faut connaître avant de chercher une tâche qui ne part pas.

ÉlémentDebian, UbuntuRed Hat, Rocky, Oracle Linux, Fedora
paquetcroncronie
nom du servicecron.servicecrond.service
tables utilisateur/var/spool/cron/crontabs//var/spool/cron/
journal/var/log/syslog ou journalctl -u cron/var/log/cron ou journalctl -u crond
fichiers de droits/etc/cron.allow, /etc/cron.deny/etc/cron.allow, /etc/cron.deny

Le démon cron se contrôle comme tout service systemd : systemctl status cron sur Debian, systemctl status crond sur Red Hat. Un service arrêté explique à lui seul qu'aucune tâche ne parte, et la commande crontab continue pourtant d'accepter les modifications sans rien signaler.

Comment vérifier les tâches cron programmées et leur exécution ?

Pour vérifier les tâches cron d'un compte, crontab -l liste la table de l'utilisateur courant et sudo crontab -u username -l celle d'un autre compte. Les tâches du système se lisent dans /etc/crontab, /etc/cron.d/ et les répertoires cron.daily et voisins ; une boucle sur /var/spool/cron/crontabs/ (Debian) donne la liste complète pour tous les utilisateurs.

Savoir qu'une tâche existe ne dit pas qu'elle a tourné. Le démon cron écrit une ligne dans le journal système à chaque lancement : grep CRON /var/log/syslog sur Debian, tail /var/log/cron sur Red Hat, ou journalctl -u cron --since today sur toute machine avec systemd. Cette ligne prouve le lancement, pas le succès de la commande.

Pour connaître le résultat, le script doit écrire son propre log. La redirection >> /home/site/logs/cron.log 2>&1 ajoute la sortie standard et les erreurs au même fichier ; un horodatage en tête de chaque passage (echo "$(date) debut" dans le script) permet de retrouver une exécution précise. À l'inverse, > /dev/null 2>&1 jette toute sortie : à réserver aux tâches éprouvées.

La variable MAILTO, placée en tête de crontab, envoie la sortie de chaque tâche par courriel à l'adresse indiquée, à condition qu'un serveur de messagerie local fonctionne. MAILTO="" désactive ces envois ; sans la variable, le courrier part vers la boîte locale de l'utilisateur, que personne ne lit.

Trois pièges qui font échouer une tâche cron

Une tâche cron qui marche dans le terminal et échoue sous cron souffre presque toujours de l'un de ces trois défauts.

  1. L'environnement réduit. Cron ne charge ni .bashrc ni .profile : la variable PATH se limite à /usr/bin:/bin sur la plupart des systèmes, sans /usr/local/bin ni /usr/local/sbin. Écrire les chemins complets des programmes (/usr/bin/php plutôt que php) évite les « commande introuvable ». Une ligne PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin en tête de crontab règle la question pour toutes les lignes.
  2. Le signe pourcentage. Dans une crontab, % signifie un retour à la ligne, et ce qui suit part sur l'entrée standard de la commande. Une date dans un nom de fichier s'écrit donc date +\%F, avec la barre oblique inverse. Le problème disparaît si la commande vit dans un script : le % n'y a rien de spécial.
  3. Le répertoire courant. Cron lance la commande depuis le dossier personnel de l'utilisateur. Un script qui ouvre config.php sans chemin le cherche là, et non dans le dossier du site. Un cd /home/site/www && en début de commande, ou des chemins absolus dans le script, lève l'ambiguïté.

Un quatrième cas touche les droits : un script sans bit d'exécution (chmod +x) ou sans ligne #!/bin/sh en tête ne démarre pas. Les fichiers /etc/cron.allow et /etc/cron.deny décident en outre qui a le droit d'utiliser crontab : si cron.allow existe, seuls les comptes qu'il nomme y ont accès ; sinon, les comptes listés dans cron.deny en sont exclus.

Exemple : exporter une base MySQL ou MariaDB chaque nuit

L'export nocturne d'une base de données reste l'usage le plus courant de cron sur un serveur web. La première règle concerne le mot de passe : il ne doit pas figurer dans la ligne cron, visible dans la liste des processus. Il se range dans un fichier d'options, ~/.my.cnf, rendu lisible par le seul propriétaire avec chmod 600 :

[client]
user=site_sauvegarde
password=motdepasse-long-et-unique

Le script, enregistré ici sous /home/site/bin/sauvegarde.sh, appelle ensuite le client d'export. Sur MariaDB, il s'appelle mariadb-dump ; l'ancien nom mysqldump n'y reste qu'en lien symbolique, déprécié depuis la version 11.0 selon la documentation de MariaDB. Sur MySQL, il s'appelle toujours mysqldump. L'option --single-transaction donne une copie cohérente des tables InnoDB sans les verrouiller ; les tables MyISAM, elles, ne bénéficient pas de cette cohérence.

#!/bin/sh
D=$(date +%F)
echo "$(date) debut export" >> /home/site/logs/cron.log
/usr/bin/mariadb-dump --single-transaction --quick ma_base | gzip > /home/site/sauvegardes/ma_base-$D.sql.gz
find /home/site/sauvegardes -name '*.sql.gz' -mtime +14 -delete

La ligne de crontab correspondante lance ce script à 2 h 30 chaque nuit et garde sa trace :

30 2 * * * /home/site/bin/sauvegarde.sh >> /home/site/logs/cron.log 2>&1

La dernière ligne du script efface les exports de plus de quatorze jours pour ne pas saturer l'espace disque. Le % de date n'a pas besoin d'être protégé, puisqu'il se trouve dans le script et non dans la crontab. Une sauvegarde jamais restaurée reste une hypothèse : importer l'un des fichiers dans une base de test, de temps en temps, vérifie qu'elle est exploitable.

Programmer des tâches avec cron sur un hébergement sans accès SSH

Les offres mutualisées donnent rarement accès à crontab -e. Le panneau d'administration propose alors un écran de tâches planifiées qui remplit les mêmes cinq champs de temps, ou qui appelle une adresse web à intervalle régulier. L'intervalle minimal varie selon l'hébergeur : certains refusent un passage chaque minute et imposent un pas de quelques minutes.

Un script PHP lancé de cette façon tourne avec la configuration de la ligne de commande (PHP CLI), dont les limites de temps et de mémoire diffèrent souvent de celles du site. Certaines fonctions qu'il utiliserait, comme exec, peuvent aussi y être désactivées : la question des fonctions interdites dans PHP explique pourquoi et comment s'en passer. Les versions de PHP et les limites du serveur sont traitées dans la rubrique PHP et serveurs.

Quand seule une tâche par appel d'URL existe, le script doit refuser les appels venus d'ailleurs, par un jeton secret dans l'adresse ou un contrôle de l'adresse IP, sous peine de voir n'importe quel visiteur déclencher l'export.

Cron ou timer systemd : lequel garder pour une tâche régulière ?

Les timers systemd forment l'alternative moderne à cron sur Linux : un fichier .timer déclenche un fichier .service à heure fixe. Ils apportent un journal par tâche dans journalctl, le rattrapage des passages manqués (Persistent=true) et un décalage aléatoire pour étaler la charge (RandomizedDelaySec).

Cron garde pour lui la simplicité : une ligne au lieu de deux fichiers de configuration, une syntaxe connue de tous les administrateurs et disponible sur tous les systèmes Unix. Pour quelques scripts de site, la crontab suffit largement ; pour des dizaines de tâches système avec dépendances entre services, les timers deviennent plus lisibles.

Tâches cron qui ne partent pas, ou partent deux fois

Comment supprimer une tâche cron sans effacer les autres ?

Pour supprimer une tâche cron, crontab -e ouvre la table et il suffit d'effacer la ligne voulue, ou de la commenter avec un # pour la garder en réserve. La commande crontab -r efface toute la table d'un coup, sans retour possible si aucune copie n'existe.

Pourquoi une tâche cron tourne-t-elle à une heure décalée ?

Cron suit le fuseau horaire du système, souvent UTC sur un serveur loué. Une tâche réglée sur 2 h UTC part à 3 h ou 4 h à Paris selon la saison. La commande timedatectl affiche le fuseau en vigueur sur la machine.

Pourquoi un script cron s'exécute-t-il deux fois ?

Un script cron qui s'exécute deux fois figure presque toujours dans deux tables à la fois, par exemple dans la crontab de l'utilisateur et dans /etc/cron.d/, ou dure plus longtemps que l'intervalle entre deux passages. La commande flock (flock -n /tmp/export.lock script.sh) empêche un second lancement tant que le premier tourne.

Sources : pages de manuel crontab(1), crontab(5) et cron(8) de Linux, manuel de run-parts (Debian), documentation de MariaDB sur mariadb-dump (options --single-transaction et --quick), manuel de référence MySQL sur mysqldump et les fichiers d'options, documentation systemd.timer.

Dernières réponses

Questions proches

▲