Retour au blog

Publié le · 9 min de lecture

Les expressions cron de zéro : un guide visuel

Apprenez la syntaxe POSIX cron à 5 champs, les caractères spéciaux, les valeurs de pas, les extensions Quartz, les différences AWS cron, et une dizaine d'exemples concrets que vous pouvez copier-coller dans une crontab dès aujourd'hui.

Pourquoi cron est encore partout

Cron a été écrit par Brian Kernighan pour Unix Version 7 en 1979. La version que la plupart des systèmes Linux modernes embarquent encore — Vixie cron, écrit par Paul Vixie en 1987 — a ajouté les variables d'environnement, les crontabs par utilisateur et le sympathique raccourci @reboot, mais elle a conservé le format de planification original à cinq champs presque intact. Cette stabilité est précisément la raison pour laquelle une syntaxe conçue avant l'existence du World Wide Web est encore collée dans des manifestes Kubernetes, des workflows GitHub Actions, des règles AWS EventBridge et des annotations Spring @Scheduled en 2026.

Si vous n'apprenez cron qu'en copiant des lignes depuis Stack Overflow, la planification finit par faire quelque chose d'inattendu — votre sauvegarde quotidienne s'exécute toutes les minutes, votre tâche de week-end se déclenche le mardi, votre fuseau horaire bascule à un changement d'heure. Ce guide parcourt la syntaxe depuis la base, puis montre suffisamment d'exemples concrets pour que vous puissiez reconnaître la forme de n'importe quelle expression d'un coup d'œil.

Le format à 5 champs

Une ligne crontab POSIX est une planification suivie d'une commande. La planification compte exactement cinq champs séparés par des espaces : minute, heure, jour du mois, mois, jour de la semaine. Chaque champ accepte un nombre, une liste, une plage, un pas, ou le caractère générique *.

* * * * *  command-to-run
┬ ┬ ┬ ┬ ┬
│ │ │ │ │
│ │ │ │ └─── day of week   (0-6, Sunday = 0; 7 also = Sunday on most cron implementations)
│ │ │ └───── month          (1-12, or JAN-DEC)
│ │ └─────── day of month   (1-31)
│ └───────── hour           (0-23)
└─────────── minute         (0-59)

Caractères spéciaux : * , - / et leurs amis

Cinq caractères font presque tout le travail dans le cron classique. Apprenez ce que chacun signifie et la plupart des expressions se lisent comme une phrase.

  • * — toute valeur dans ce champ. * dans le champ minute signifie « chaque minute ».
  • , — liste de valeurs discrètes. 0,15,30,45 dans le champ minute signifie quatre minutes fixes par heure.
  • - — plage inclusive. 1-5 dans le champ jour de la semaine signifie du lundi au vendredi.
  • / — valeur de pas, écrite sous la forme plage/pas ou */pas. */10 dans minute signifie « toutes les 10 minutes en partant de 0 ».
  • L, W, # — extensions Quartz, ne font pas partie de POSIX. L = dernier, W = jour de semaine le plus proche, # = nième jour de la semaine du mois. Plus de détails ci-dessous.
0,30 * * * *      at :00 and :30 every hour
*/5 * * * *       every 5 minutes (0, 5, 10, 15 ...)
0 9-17 * * 1-5    every hour from 09:00 to 17:00, Mon-Fri
0 0 1,15 * *      midnight on the 1st and 15th of every month
15 14 * * 0       14:15 every Sunday

Les valeurs de pas ne sont pas ce que vous croyez

L'opérateur de pas / fonctionne toujours par rapport à une plage, même quand cette plage est implicite. */15 dans le champ minute est un raccourci pour 0-59/15, qui se déclenche à 0, 15, 30 et 45. C'est pourquoi */7 dans minute ne signifie PAS « toutes les 7 minutes à partir de maintenant » — cela signifie « les multiples de 7 entre 0 et 59 », ce qui vous donne 0, 7, 14, 21, 28, 35, 42, 49, 56 puis un écart de 4 minutes avant que minuit ne bascule. Si vous avez besoin d'un véritable intervalle glissant, utilisez un exécuteur de tâches ou un timer systemd avec OnUnitActiveSec.

Les pas peuvent aussi commencer en cours de plage. 5-59/10 dans minute se déclenche à 5, 15, 25, 35, 45, 55. Combinez plages et pas quand vous voulez une planification non symétrique sans écrire une liste géante de virgules.

*/15 * * * *      00, 15, 30, 45  (good)
*/7 * * * *       00, 07, 14, 21, 28, 35, 42, 49, 56, then a 4-min gap (probably not what you want)
5-59/10 * * * *   05, 15, 25, 35, 45, 55
0 */4 * * *       00:00, 04:00, 08:00, 12:00, 16:00, 20:00

Jour du mois et jour de la semaine : la règle OR

Le plus gros piège de cron : quand le jour du mois et le jour de la semaine sont tous deux restreints (aucun des deux n'est *), Vixie cron les traite comme un OU logique, pas un ET. La ligne 0 0 13 * 5 se déclenche à minuit le 13 de chaque mois ET chaque vendredi — pas seulement le vendredi 13. Pour obtenir le comportement ET, restreignez un seul des deux champs et filtrez l'autre dans votre script, ou utilisez un planificateur comme Quartz qui prend en charge le placeholder ? pour « aucune valeur spécifique ».

0 0 13 * 5        midnight on the 13th OR any Friday  (Vixie cron OR rule)
0 0 * * 5         every Friday at midnight
0 0 13 * *        every 13th of the month at midnight
# Quartz: 0 0 0 13 * 5 ?   would match Friday the 13th specifically

Dix exemples à copier-coller

Imprimez ce tableau et collez-le à côté de votre moniteur. La plupart des lignes cron de production que vous écrirez ne sont que des variations mineures de celles-ci.

* * * * *           every minute
0 * * * *           every hour at :00
*/15 * * * *        every 15 minutes
0 0 * * *           every day at midnight (server local time)
0 9 * * 1-5         weekdays at 09:00
30 14 * * 1-5       weekdays at 14:30
0 9 * * 1           every Monday at 09:00
0 22 * * 0          every Sunday at 22:00
0 0 1 * *           midnight on the 1st of every month
0 0 1 1 *           midnight on January 1st
0 3 * * 6           every Saturday at 03:00 (typical backup window)
*/5 9-17 * * 1-5    every 5 minutes during business hours, Mon-Fri

Raccourcis nommés

Vixie cron, GNU mcron et la plupart de leurs descendants acceptent une poignée d'alias préfixés par @ qui correspondent à des planifications courantes. Ils sont plus faciles à lire que les cinq champs équivalents et plus difficiles à tromper.

@yearly    same as 0 0 1 1 *      (also @annually)
@monthly   same as 0 0 1 * *
@weekly    same as 0 0 * * 0
@daily     same as 0 0 * * *      (also @midnight)
@hourly    same as 0 * * * *
@reboot    run once at system startup

Quartz : le cousin à 6 et 7 champs

Les planificateurs Java — Quartz lui-même, le @Scheduled de Spring avec cron =, et une poignée de plateformes cloud — utilisent un dialecte différent. Quartz ajoute un champ secondes au début et, optionnellement, un champ année à la fin, donnant un total de six ou sept champs. Il prend également en charge L (dernier), W (jour de semaine le plus proche), # (nième jour de la semaine du mois) et le placeholder ? signifiant « aucune valeur spécifique, seul l'un des champs jour du mois et jour de la semaine est défini ».

Si vous copiez une expression Quartz dans une crontab Linux, elle sera silencieusement mal analysée, car le 0 de tête ressemble à une valeur minute normale pour Vixie cron. Sachez toujours quel dialecte votre planificateur attend avant d'enregistrer le fichier.

Quartz fields: second minute hour day-of-month month day-of-week [year]

0  0  12  *  *  ?           every day at noon
0  15 10  ?  *  MON-FRI     weekdays at 10:15
0  0  0   L  *  ?           last day of every month at midnight
0  0  0   LW *  ?           last weekday of every month
0  0  9   ?  *  2#1         first Monday of every month at 09:00
0  0  9   ?  *  6#3         third Friday of every month at 09:00
0  0  0   1  *  ?  2026     midnight on the 1st of every month, but only in 2026

AWS : expressions rate vs cron

EventBridge, CloudWatch Events et Lambda utilisent une syntaxe cron proche de Quartz avec deux écarts importants. Il n'y a pas de champ secondes (six champs, pas sept) et vous devez utiliser ? dans soit jour du mois, soit jour de la semaine — jamais les deux comme *. AWS propose également rate(value unit) pour les intervalles simples, ce qui évite entièrement le piège du OR.

AWS cron fields: minute hour day-of-month month day-of-week year

cron(0 12 * * ? *)        every day at 12:00 UTC
cron(0/15 * * * ? *)      every 15 minutes
cron(0 9 ? * MON-FRI *)   weekdays at 09:00 UTC
cron(0 0 1 * ? *)         midnight UTC on the 1st of every month

rate(5 minutes)           every 5 minutes
rate(1 hour)              every hour
rate(7 days)              every 7 days starting from rule creation

Fuseaux horaires, heure d'été et les choses qui cassent à 02h30

Vixie cron honore le fuseau horaire système (variable d'environnement TZ, ou ce vers quoi pointe /etc/localtime). Quand l'heure d'été saute une heure en avant, toute tâche planifiée à l'intérieur de l'écart est silencieusement ignorée. Quand l'heure d'été recule, les tâches planifiées dans l'heure dupliquée s'exécutent deux fois sur certaines implémentations et une seule fois sur d'autres. Les deux valeurs par défaut sûres : exécuter cron en UTC, ou planifier en dehors de la fenêtre 01h00-04h00.

Les planificateurs cloud se comportent différemment. EventBridge fonctionne toujours en UTC. Les CronJobs Kubernetes honorent le champ spec.timeZone ajouté en v1.27. Quartz utilise le fuseau par défaut de la JVM sauf si vous passez un CronTrigger avec un fuseau horaire. Lisez toujours la documentation une fois pour le planificateur que vous configurez ; ne supposez pas que la convention du précédent se reporte.

Déboguer une expression qui ne se déclenche pas

Neuf fois sur dix, l'expression elle-même est correcte et c'est l'environnement qui cloche. Parcourez cette liste de contrôle avant de blâmer la planification.

  • Lisez le journal du démon cron : grep CRON /var/log/syslog sur Debian/Ubuntu, journalctl -u cron sur les hôtes systemd. Le journal montre la ligne de commande résolue que cron a réellement exécutée.
  • Confirmez l'utilisateur. crontab -l sans option affiche VOTRE crontab ; la planification qui vous intéresse peut être dans /etc/crontab, /etc/cron.d/*, ou la crontab d'un autre utilisateur.
  • Vérifiez le PATH. Cron tourne avec un PATH minimal (généralement /usr/bin:/bin). Utilisez des chemins absolus ou définissez PATH= en haut de la crontab.
  • Vérifiez le shell. Cron utilise /bin/sh, pas votre shell de connexion. Tout ce qui est spécifique à bash (substitution de processus, [[ )) nécessite un wrapper bash -c explicite.
  • Redirigez la sortie. Sans > /var/log/myjob.log 2>&1 une tâche en échec envoie un e-mail à root localement et vous ne le voyez jamais.
  • Confirmez le fuseau horaire. date && date -u dans la tâche journalise les deux. S'ils contredisent ce que votre planification supposait, c'est votre bogue.
# A safer cron line:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""

*/5 * * * *  /usr/local/bin/sync.sh >> /var/log/sync.log 2>&1

Quand cron est le mauvais outil

Cron est excellent pour les planifications fixes basées sur l'heure murale et imbattable pour les tâches d'une ligne sur un seul hôte. Il est mal adapté quand vous avez besoin de : coordination distribuée sur plusieurs machines (utilisez une file, un planificateur avec élection de leader, ou des CronJobs Kubernetes avec concurrencyPolicy: Forbid) ; relances et back-off sur échec (encapsulez le script ou utilisez un moteur de workflow) ; granularité inférieure à la minute (utilisez un timer systemd ou un déclencheur événementiel) ; ou planifications qui dépendent de la fin de l'exécution précédente (cron démarrera joyeusement une seconde copie pendant que la première tourne encore). Reconnaître la limite tôt épargne beaucoup d'astreintes à 3 heures du matin.

Construire et vérifier visuellement

Si vous écrivez plus de quelques lignes cron par mois, l'habitude la plus rentable est de vérifier chaque expression contre un parseur avant de la committer. Multilities propose un /tools/cron-builder gratuit qui décode une expression à 5 ou 6 champs en français clair et affiche les dix prochains déclenchements dans votre fuseau horaire local, ce qui est exactement le contre-contrôle qui attrape le piège OR jour du mois / jour de la semaine et la surprise des pas façon */7. Associez cela à un test unitaire rapide qui vérifie le prochain déclenchement pour une date d'ancrage connue et vos tâches planifiées deviennent ennuyeusement fiables — ce que vous voulez qu'elles soient.

Essayez ces outils