Zurück zum Blog

Veröffentlicht · 8 Min. Lesezeit

Cron-Ausdrücke von Grund auf: Ein visuelles Tutorial

Lernen Sie die fünf Felder der POSIX-Cron-Syntax, Sonderzeichen, Schrittwerte, Quartz-Erweiterungen, die AWS-Cron-Besonderheiten und ein Dutzend ausgearbeitete Beispiele, die Sie heute noch in eine crontab kopieren können.

Warum Cron immer noch überall ist

Cron wurde 1979 von Brian Kernighan für Version 7 Unix geschrieben. Die Variante, die die meisten modernen Linux-Systeme noch immer ausliefern - Vixie cron, 1987 von Paul Vixie verfasst - fügte Umgebungsvariablen, benutzerspezifische crontabs und die praktische @reboot-Abkürzung hinzu, ließ das ursprüngliche Fünf-Felder-Format der Zeitplanung aber fast unverändert. Genau diese Stabilität ist der Grund, warum eine Syntax, die vor dem World Wide Web entworfen wurde, im Jahr 2026 immer noch in Kubernetes-Manifeste, GitHub-Actions-Workflows, AWS-EventBridge-Regeln und Spring-@Scheduled-Annotationen kopiert wird.

Wenn Sie Cron nur durch Kopieren von Stack-Overflow-Zeilen lernen, macht der Zeitplan irgendwann etwas, das Sie nicht erwartet haben - Ihr tägliches Backup läuft jede Minute, Ihr Wochenendjob startet dienstags, Ihre Zeitzone verschiebt sich an einer DST-Grenze. Dieser Leitfaden durchläuft die Syntax von Grund auf und zeigt anschließend genügend ausgearbeitete Beispiele, damit Sie die Form jedes Ausdrucks auf einen Blick erkennen.

Das 5-Felder-Format

Eine POSIX-crontab-Zeile ist ein Zeitplan gefolgt von einem Befehl. Der Zeitplan besteht aus genau fünf durch Leerzeichen getrennten Feldern: Minute, Stunde, Tag des Monats, Monat, Wochentag. Jedes Feld akzeptiert eine Zahl, eine Liste, einen Bereich, einen Schritt oder den Platzhalter *.

* * * * *  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)

Sonderzeichen: * , - / und Verwandte

Fünf Zeichen erledigen in klassischem Cron fast die ganze Arbeit. Lernen Sie, was jedes davon bedeutet, und die meisten Ausdrücke lesen sich wie ein Satz.

  • * - jeder Wert in diesem Feld. * im Minutenfeld bedeutet "jede Minute".
  • , - Liste diskreter Werte. 0,15,30,45 im Minutenfeld bedeutet vier feste Minuten pro Stunde.
  • - - inklusiver Bereich. 1-5 im Wochentagsfeld bedeutet Montag bis Freitag.
  • / - Schrittwert, geschrieben als Bereich/Schritt oder */Schritt. */10 in Minute bedeutet "alle 10 Minuten beginnend bei 0".
  • L, W, # - Quartz-Erweiterungen, nicht Teil von POSIX. L = letzter, W = nächster Werktag, # = n-ter Wochentag des Monats. Mehr dazu unten.
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

Schrittwerte sind nicht das, was Sie denken

Der Schrittoperator / arbeitet immer gegen einen Bereich, auch wenn der Bereich implizit ist. */15 im Minutenfeld ist die Kurzschreibweise für 0-59/15 und feuert bei 0, 15, 30 und 45. Deshalb bedeutet */7 in Minute NICHT "alle 7 Minuten ab jetzt", sondern "die Vielfachen von 7 zwischen 0 und 59", also 0, 7, 14, 21, 28, 35, 42, 49, 56 und dann eine Lücke von 4 Minuten, bevor Mitternacht überrollt wird. Wenn Sie wirklich ein rollendes Intervall brauchen, nutzen Sie einen Job-Runner oder einen systemd-Timer mit OnUnitActiveSec.

Schritte können auch mittendrin in einem Bereich beginnen. 5-59/10 in Minute feuert bei 5, 15, 25, 35, 45, 55. Kombinieren Sie Bereiche und Schritte, wenn Sie einen asymmetrischen Zeitplan ohne eine riesige Kommaliste wollen.

*/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

Tag des Monats und Wochentag: die ODER-Regel

Der größte Stolperstein in Cron: Wenn sowohl Tag-des-Monats als auch Wochentag eingeschränkt sind (keiner ist *), behandelt Vixie cron sie als logisches ODER, nicht als UND. Die Zeile 0 0 13 * 5 feuert um Mitternacht am 13. eines jeden Monats UND an jedem Freitag - nicht nur am Freitag, den 13. Um das UND-Verhalten zu erhalten, schränken Sie nur eines der beiden Felder ein und filtern Sie das andere in Ihrem Skript, oder verwenden Sie einen Scheduler wie Quartz, der den Platzhalter ? für "kein spezifischer Wert" unterstützt.

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

Zehn Beispiele zum Kopieren

Drucken Sie diese Tabelle aus und kleben Sie sie neben Ihren Monitor. Die meisten Produktions-Cron-Zeilen, die Sie je schreiben, sind kleine Variationen davon.

* * * * *           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

Benannte Abkürzungen

Vixie cron, GNU mcron und die meisten Nachfahren akzeptieren eine Handvoll @-präfigierter Aliase, die auf gängige Zeitpläne abbilden. Sie sind leichter zu lesen als die entsprechenden fünf Felder und schwerer falsch zu tippen.

@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: der Cousin mit 6 und 7 Feldern

Java-Scheduler - Quartz selbst, Springs @Scheduled mit cron =, und eine Handvoll Cloud-Plattformen - nutzen einen anderen Dialekt. Quartz stellt ein Sekundenfeld voran und hängt optional ein Jahresfeld an, was insgesamt sechs oder sieben Felder ergibt. Außerdem unterstützt Quartz L (last), W (nearest weekday), # (n-ter Wochentag des Monats) und den Platzhalter ?, der "kein spezifischer Wert, nur eines von Tag-des-Monats und Wochentag ist gesetzt" bedeutet.

Wenn Sie einen Quartz-Ausdruck in eine Linux-crontab kopieren, wird er still falsch geparst, weil die führende 0 für Vixie cron wie ein normaler Minutenwert aussieht. Wissen Sie immer, welchen Dialekt Ihr Scheduler erwartet, bevor Sie die Datei speichern.

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-Rate- vs. Cron-Ausdrücke

EventBridge, CloudWatch Events und Lambda verwenden eine an Quartz angelehnte Cron-Syntax mit zwei wichtigen Abweichungen. Es gibt kein Sekundenfeld (sechs Felder, nicht sieben), und Sie müssen ? entweder in Tag-des-Monats oder Wochentag verwenden - niemals beide als *. AWS bietet außerdem rate(value unit) für einfache Intervalle, was die ODER-Falle vollständig vermeidet.

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

Zeitzonen, Sommerzeit und die Dinge, die um 02:30 brechen

Vixie cron respektiert die Systemzeitzone (Umgebungsvariable TZ, oder worauf /etc/localtime verweist). Wenn die Sommerzeit eine Stunde vorspringt, wird jeder Job, der innerhalb der Lücke geplant ist, still übersprungen. Wenn die Sommerzeit zurückfällt, laufen Jobs innerhalb der duplizierten Stunde auf manchen Implementierungen zweimal und auf anderen einmal. Die beiden sicheren Standardeinstellungen: Cron in UTC laufen lassen oder außerhalb des Fensters 01:00-04:00 planen.

Cloud-Scheduler verhalten sich anders. EventBridge läuft immer in UTC. Kubernetes CronJobs respektieren das Feld spec.timeZone, das in v1.27 hinzugefügt wurde. Quartz nutzt die JVM-Standardzeitzone, sofern Sie nicht einen CronTrigger mit Zeitzone übergeben. Lesen Sie die Doku einmal für jeden Scheduler, den Sie konfigurieren; gehen Sie nicht davon aus, dass die Konvention vom letzten übernommen wird.

Einen Ausdruck debuggen, der nicht feuert

Neun von zehn Mal ist der Ausdruck selbst in Ordnung, und die Umgebung ist falsch. Gehen Sie diese Checkliste durch, bevor Sie den Zeitplan beschuldigen.

  • Lesen Sie das Log des Cron-Daemons: grep CRON /var/log/syslog auf Debian/Ubuntu, journalctl -u cron auf systemd-Hosts. Das Log zeigt die aufgelöste Kommandozeile, die Cron tatsächlich ausgeführt hat.
  • Bestätigen Sie den Benutzer. crontab -l ohne Flag zeigt IHRE crontab; der Zeitplan, der Sie interessiert, kann in /etc/crontab, /etc/cron.d/* oder in der crontab eines anderen Benutzers liegen.
  • Prüfen Sie PATH. Cron läuft mit einem minimalen PATH (meist /usr/bin:/bin). Verwenden Sie absolute Pfade oder setzen Sie PATH= am Anfang der crontab.
  • Prüfen Sie die Shell. Cron nutzt /bin/sh, nicht Ihre Login-Shell. Alles bash-spezifische (Prozesssubstitution, [[ )) braucht einen expliziten bash -c -Wrapper.
  • Leiten Sie die Ausgabe um. Ohne > /var/log/myjob.log 2>&1 mailt ein fehlschlagender Job lokal an root, und Sie sehen es nie.
  • Bestätigen Sie die Zeitzone. date && date -u innerhalb des Jobs protokolliert beides. Wenn sie nicht mit dem übereinstimmen, was Ihr Zeitplan annahm, ist das Ihr Bug.
# 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

Wann Cron das falsche Werkzeug ist

Cron ist hervorragend für feste wandzeitbezogene Zeitpläne und unschlagbar für einzeilige Jobs auf einem einzelnen Host. Es passt schlecht, wenn Sie brauchen: verteilte Koordination über viele Maschinen (nutzen Sie eine Queue, einen leadergewählten Scheduler oder Kubernetes CronJobs mit concurrencyPolicy: Forbid); Wiederholungen und Backoff bei Fehlern (umhüllen Sie das Skript oder nutzen Sie eine Workflow-Engine); Sub-Minuten-Granularität (nutzen Sie einen systemd-Timer oder einen ereignisgesteuerten Trigger); oder Zeitpläne, die davon abhängen, dass der vorige Lauf zuerst fertig ist (Cron startet fröhlich eine zweite Kopie, während die erste noch läuft). Diese Grenze früh zu erkennen, erspart eine Menge Pager-Alarme um 3 Uhr morgens.

Visuell bauen und überprüfen

Wenn Sie mehr als ein paar Cron-Zeilen pro Monat schreiben, ist die wirksamste Gewohnheit, jeden Ausdruck mit einem Parser zu prüfen, bevor Sie ihn einchecken. Multilities bietet einen kostenlosen /tools/cron-builder, der einen 5- oder 6-Felder-Ausdruck in einfaches Deutsch übersetzt und die nächsten zehn Auslösezeiten in Ihrer lokalen Zeitzone anzeigt - genau die Gegenprobe, die die Tag-des-Monats/Wochentag-ODER-Falle und die */7-Schrittüberraschung aufdeckt. Kombinieren Sie das mit einem schnellen Unit-Test, der die nächste Auslösezeit für ein bekanntes Ankerdatum prüft, und Ihre geplanten Jobs werden langweilig zuverlässig - und genau das sollen sie sein.

Probiere diese Tools aus