Skip to content

Guide

Tutoriel sur les expressions cron : lire et écrire des planifications crontab

Cinq champs, six caractères spéciaux, et un bug historique qui décide si votre tâche s’exécute une ou deux fois.

By Published

Cron a quarante ans et reste le planificateur par défaut sur presque tous les systèmes Unix livrés cette année. La syntaxe tient sur une ligne, ce qui explique en grande partie pourquoi il a survécu — et aussi pourquoi il est régulièrement mal lu. Ce guide passe en revue les cinq champs, chaque caractère spécial, le piège jour-du-mois contre jour-de-la-semaine, et une petite bibliothèque d’expressions que vous pouvez copier directement dans un crontab.

L’anatomie en cinq champs

Une expression cron POSIX comporte cinq champs séparés par des espaces, dans cet ordre :

# ┌──────────── minute        (0 - 59)
# │ ┌────────── heure          (0 - 23)
# │ │ ┌──────── jour du mois  (1 - 31)
# │ │ │ ┌────── mois         (1 - 12)  ou JAN-DEC
# │ │ │ │ ┌──── jour de la semaine   (0 - 6)   ou SUN-SAT, 0 et 7 = dimanche
# │ │ │ │ │
  *  *  *  *  *   commande-à-exécuter

Chaque champ doit être présent. Il n’y a pas de valeurs par défaut et pas de raccourcis positionnels. Un champ avec *signifie “chaque valeur valide dans cette plage,” pas “ignorer.” Cette distinction compte dès que vous commencez à combiner des champs.

Certaines variantes ajoutent un sixième champ secondes au début (Quartz,@Scheduled de Spring) ou un septième champ année à la fin. Ce sont des extensions, pas POSIX. Pour la portabilité, restez à cinq.

Pourquoi deux champs de jour ?

Cron permet de dire “chaque lundi” et “le premier du mois” sur la même ligne, ce qui serait ambigu si les deux champs devaient s’accorder. La résolution historique est une sémantique OU quand les deux champs sont restreints : la tâche se déclenche quand le jour-du-mois oule jour-de-la-semaine correspond. Nous y reviendrons ; c’est le bug cron le plus courant.

Caractères spéciaux

Chaque champ accepte six caractères spéciaux. Leur comportement est identique dans tous les champs, mais la plage valide diffère évidemment par champ.

* — chaque valeur

Correspond à chaque valeur valide dans le champ. * * * * * signifie chaque minute de chaque heure de chaque jour. C’est la seule expression qui se déclenche vraiment soixante fois par heure ; tout ce qui est plus complexe se déclenche généralement moins.

, — liste

La virgule sépare les valeurs discrètes. 0,15,30,45 * * * * se déclenche au début, à et quart, à la demie et au trois-quarts de chaque heure. L’ordre n’importe pas pour l’analyseur, mais les lecteurs apprécient les listes croissantes.

- — plage

Le tiret définit une plage inclusive. 0 9-17 * * 1-5 se déclenche au début de chaque heure de 09:00 à 17:00 inclus, du lundi au vendredi. Les deux extrémités sont incluses ; c’est neuf exécutions par jour, pas huit.

/ — pas

La barre oblique applique un pas à une plage. */5 dans le champ des minutes est un raccourci pour 0-59/5 — toutes les cinq minutes à partir de la minute 0. Vous pouvez combiner le pas avec une plage explicite : 0-30/10 se déclenche à 0, 10, 20, 30 et nulle part ailleurs.

? — aucune valeur spécifique (Quartz uniquement)

Le caractère ? n’est pasPOSIX. Il apparaît dans le cron de style Quartz (et AWS EventBridge) et signifie “aucune valeur spécifique — l’autre champ de jour fait autorité.” Vous écrirez 0 9 ? * MON-FRI dans EventBridge mais 0 9 * * MON-FRI dans le cron classique.

Valeurs nommées

Les mois acceptent JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC, les jours de la semaine acceptent SUN MON TUE WED THU FRI SAT. Ils sont insensibles à la casse dans la plupart des implémentations. Les valeurs nommées ne fonctionnent pas dans les plages ou les pas sur toutes les implémentations — utilisez la forme numérique en cas de doute.

Recettes

La façon la plus rapide d’intérioriser cron est de lire quelques dizaines d’expressions avec leur traduction en anglais courant. Collez n’importe laquelle dans notre générateur d’expressions cron pour voir les dix prochains déclenchements dans votre zone locale.

Toutes les N minutes

  • * * * * * — chaque minute
  • */5 * * * * — toutes les cinq minutes, à la minute 0, 5, 10…
  • */15 * * * * — chaque quart d’heure
  • 0,30 * * * * — à l’heure et à la demi-heure
  • 5,35 * * * * — décalé de cinq minutes — utile pour étaler les tâches qui concurrencent la même base de données

Variantes horaires

  • 0 * * * * — toutes les heures pile
  • 0 */2 * * * — toutes les deux heures à partir de 00:00
  • 0 9-17 * * * — à l’heure pile, de 09:00 à 17:00 inclus

Variantes quotidiennes

  • 0 0 * * * — minuit chaque jour (équivalent à @daily)
  • 30 3 * * * — 03:30 chaque jour — la fenêtre de sauvegarde classique
  • 0 9 * * 1-5 — 09:00 les jours de semaine
  • 0 18 * * 5 — 18:00 les vendredis seulement

Hebdomadaire, mensuel, annuel

  • 0 9 * * 1 — 09:00 chaque lundi
  • 0 0 1 * * — minuit le premier de chaque mois (équivalent à @monthly)
  • 0 0 1 1 * — minuit le 1er janvier (équivalent à @yearly)

Heures de bureau

  • 0 9-17 * * 1-5 — à l’heure pile, 09:00-17:00, lundi-vendredi
  • */10 9-17 * * 1-5 — toutes les dix minutes pendant les heures de bureau
  • 0 9,13,17 * * 1-5 — ouverture, après-déjeuner, fermeture

Le piège OU jour-du-mois/jour-de-la-semaine

C’est le comportement le plus demandé dans cron, et la spec est sans ambiguïté : si les deuxchamps jour-du-mois et jour-de-la-semaine sont restreints (c’est-à-dire pas *), la tâche se déclenche quand l’une ou l’autre condition correspond, pas les deux.

Considérez 0 0 1 * 1. Une lecture naturelle est “minuit le premier du mois, mais seulement si c’est un lundi.” Le comportement réel est “minuit le premier de chaque mois,ouminuit chaque lundi.” C’est environ cinq déclenchements par mois, pas le zéro ou un que vous aviez probablement prévu.

La solution : laissez l’un des deux champs de jour comme *. Si vous avez vraiment besoin d’une sémantique ET — “premier lundi du mois” — vous devrez vérifier dans le script :

# crontab : déclencher à minuit les sept premiers jours du mois
0 0 1-7 * *  /usr/local/bin/maybe-run-monthly.sh

# dans maybe-run-monthly.sh : quitter si aujourd'hui n'est pas lundi
[ "$(date +%u)" = "1" ] || exit 0

Fuseaux horaires et heure d’été

Les expressions cron sont évaluées dans le fuseau horaire local du planificateur. Sur Linux c’est ce vers quoi /etc/localtime est lié symboliquement ; sur macOS c’est la préférence système. L’expression elle-même ne nomme jamais de zone.

Cela rend les transitions d’heure d’été intéressantes. Dans une zone observant l’heure d’été, l’horloge locale avance (une heure sautée) au printemps et recule (une heure répétée) en automne. Une tâche cron à 0 2 * * *peut ne pas se déclencher du tout le jour du passage à l’heure d’été — l’heure 02:00 n’a pas existé — et peut se déclencher deux fois en automne.

La plupart des planificateurs cloud acceptent un fuseau horaire explicite par règle ; les identifiants de zones IANA comme Europe/Paris sont corrects, CETne l’est pas. Pour une cohérence absolue, planifiez entre 03:00 et 23:00 ou exécutez le planificateur en UTC.

Erreurs courantes

Traiter la barre oblique comme une vraie période

*/Ndivise la plage du champ, donc la période entre le dernier déclenchement d’une heure et le premier de la suivante est plus courte que N. Pour un espacement strict de N minutes, cron est le mauvais outil.

Oublier que la minute 0 existe

0-59/15 se déclenche à 0, 15, 30, 45 — quatre fois par heure, pas trois. La plage commence à 0.

Supposer le PATH de la tâche

Cron s’exécute avec un environnement minimal. PATH est généralement /usr/bin:/binet vos alias shell n’existent pas. Utilisez des chemins absolus vers chaque binaire ou définissez PATH= en haut du crontab.

Carte de référence rapide

ExpressionSignification
* * * * *chaque minute
*/5 * * * *toutes les 5 minutes
0 * * * *début de chaque heure
0 9-17 * * 1-5toutes les heures, 9h-17h, jours de semaine
0 0 * * *minuit chaque jour
30 3 * * 003:30 chaque dimanche
0 0 1 * *minuit le 1er de chaque mois
0 0 1 1 *minuit le 1er janvier
@rebootune fois au démarrage du planificateur

Vérifiez avant de valider

La façon la moins chère d’éviter une alerte à 3h du matin est de coller votre expression dans un analyseur avant de sauvegarder le crontab. Notre générateur d’expressions cron affiche les dix prochains déclenchements dans votre zone locale et en UTC, plus une description en langage courant qui détecte immédiatement le piège jour-du-mois/jour-de-la-semaine.

Frequently asked questions

Cron utilise-t-il le fuseau horaire du serveur ou UTC ?
Le cron Unix classique utilise le fuseau horaire local du système, qui correspond à ce vers quoi /etc/localtime pointe. Beaucoup de planificateurs cloud (AWS EventBridge, GCP Cloud Scheduler) utilisent UTC par défaut et permettent d’opter pour une zone IANA nommée par règle. Affichez toujours le fuseau horaire résolu dans la première ligne de journal de votre tâche — cela élimine toute une catégorie de bugs post-DST.
Pourquoi ma tâche s’est-elle exécutée deux fois le matin de la fin de l’heure d’été ?
Quand les horloges reculent de 02:00 à 01:00, l’heure entre 01:00 et 02:00 se produit deux fois sur l’horloge locale. Une tâche planifiée à 01:30 dans une zone observant l’heure d’été s’exécute les deux fois sauf si votre implémentation cron dédoublonne explicitement. La solution est soit de planifier entre 03:00 et 23:00, soit d’exécuter le planificateur en UTC.
Quel est le plus petit intervalle supporté par cron ?
Une minute. Le premier champ est les minutes ; il n’y a pas de champ secondes dans le crontab POSIX. Si vous avez besoin d’une planification inférieure à la minute, utilisez un processus de longue durée avec sa propre boucle sleep, des timers systemd avec OnUnitActiveSec, ou un planificateur dédié comme Quartz qui prend en charge un champ secondes.
@hourly, @daily, @reboot sont-ils portables ?
Les chaînes raccourcies (@yearly, @monthly, @weekly, @daily, @hourly) sont prises en charge par Vixie cron, cronie et la plupart des dérivés modernes, donc elles sont sûres sous Linux et macOS. @reboot est largement pris en charge mais sa sémantique diffère — certaines implémentations s’exécutent une fois au prochain démarrage, d’autres à chaque démarrage. N’utilisez pas @reboot dans les conteneurs ; utilisez la propre commande de démarrage du conteneur à la place.
Pourquoi */7 saute-t-il parfois le dernier intervalle ?
L’opérateur de pas divise toute la plage autorisée, pas votre heure de départ. Pour les minutes (0-59), */7 se déclenche à 0, 7, 14, 21, 28, 35, 42, 49, 56 — puis la prochaine minute valide est 0 de l’heure suivante. L’écart entre 56 et 60 est de seulement quatre minutes, pas sept. Cron n’est pas un minuteur périodique.
Devrais-je utiliser cron en 2026, ou les timers systemd ?
Sur un seul hôte Linux sans orchestrateur, les timers systemd sont généralement un meilleur choix par défaut : journalisation structurée via journalctl, ordonnancement des dépendances, randomisation plus facile avec RandomizedDelaySec, et limites de ressources au niveau de l’unité. Cron gagne quand vous avez besoin de portabilité sur des systèmes non-systemd ou quand toute l’automatisation tient en une ligne de crontab. Dans les environnements orchestrés par conteneurs, ni l’un ni l’autre — utilisez le planificateur natif de la plateforme.

Related

Published May 31, 2026