🔤crontab-Syntax

Fünf Zeitfelder, dann der Befehl. Klingt einfach – bis Tag und Wochentag gleichzeitig eingeschränkt sind oder ein Tool plötzlich sechs Felder erwartet.

🧮Die fünf Felder

So steht es wörtlich als Kommentar in der /etc/crontab von Debian 13 (Paket cron 3.0pl1-197):
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *	* * *	root	cd / && run-parts --report /etc/cron.hourly
#FeldWerteNamen
1Minute0–59–
2Stunde0–23–
3Tag des Monats1–31–
4Monat1–12jan … dec
5Wochentag0–7 (0 und 7 = Sonntag)sun … sat

Nach den fünf Feldern folgt der Befehl (Rest der Zeile). Nur in /etc/crontab und /etc/cron.d/* steht dazwischen der Benutzer. Kommentare am Zeilenende gibt es nicht – ein # hinter dem Befehl wird an die Shell übergeben.

🧩Operatoren ausprobieren

Klick ein Beispiel an oder tippe selbst – die Kacheln zeigen, welche Werte das Feld auswählt.
→ alle 10 Minuten · 6 Wert(e)
01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
Step values can be used in conjunction with ranges. Following a range with "/<number>" specifies skips of the number's value through the range. For example, "0-23/2" can be used in the hours field to specify command execution every other hour […]. Steps are also permitted after an asterisk, so if you want to say "every two hours", just use "*/2".
📖 man 5 crontab (Vixie cron, Debian/macOS)
⚠️ „5/10“ ist kein klassisches cron
Ein Schritt ist laut Handbuch nur nach * oder einem Bereich erlaubt. Quartz und GitHub Actions lesen 20/15 als „ab 20 alle 15“ – in einer crontab schreibst du dafür 20-59/15. Außerdem wirken Schritte nur innerhalb des Feldes: */23 bei den Stunden heißt 0 und 23 Uhr, nicht „alle 23 Stunden“ (steht so in cronies crontab(5)).

🏷️Namen und Spezialstrings

StringentsprichtBedeutung
@reboot–einmal beim Start des cron-Daemons
@yearly0 0 1 1 *einmal im Jahr
@annually0 0 1 1 *einmal im Jahr (wie @yearly)
@monthly0 0 1 * *einmal im Monat
@weekly0 0 * * 0einmal pro Woche
@daily0 0 * * *einmal am Tag
@midnight0 0 * * *einmal am Tag (wie @daily)
@hourly0 * * * *einmal pro Stunde
💡 Namen: nur drei Buchstaben
mon, FRI, jan – Groß-/Kleinschreibung egal, monday ist ungültig. Bereiche aus Namen (mon-fri): cronie sagt „Ranges and lists of names are allowed“, das Vixie-Handbuch (Debian, macOS) dagegen „Ranges or lists of names are not allowed“. Mit Zahlen (1-5) ist man überall sicher.
⚠️ @-Strings sind Erweiterungen
Sie stehen im Vixie-Handbuch unter „EXTENSIONS“. GitHub Actions unterstützt sie ausdrücklich nicht, bei BusyBox sind sie eine Build-Option (FEATURE_CROND_SPECIAL_TIMES). Und Achtung: systemd weekly ist Montag 00:00, cron @weekly ist Sonntag 00:00.

🔀Die ODER-Regel: Tag des Monats und Wochentag

Minute, Stunde und Monat müssen immer passen. Bei den beiden Tagesfeldern gilt aber eine Sonderregel – die Ursache vieler „warum läuft das jeden Freitag?“-Fragen.
Note: The day of a command's execution can be specified by two fields — day of month, and day of week. If both fields are restricted (i.e., aren't *), the command will be run when either field matches the current time. For example, "30 4 1,15 * 5" would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday.
📖 man 5 crontab, Debian 13 (cron 3.0pl1-197) – gleichlautend bei cronie und macOS
POSIX specifies that the day of month and the day of week fields both need to match the current time if either of them is a *. However, this implementation only checks if the first character is a *. This is why "0 0 */2 * sun" runs every Sunday that's an uneven date while the POSIX standard would have it run every Sunday and on every uneven date.
📖 man 5 crontab, Debian 13, Abschnitt LIMITATIONS
0 0*
Vixie cron / cronie / Debian
beide Felder ohne führendes * → ODER · 7 Tage
Mo
Di
Mi
Do
Fr
Sa
So
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
BusyBox crond
eingeschränkt = Wertemenge unvollständig · 7 Tage
Mo
Di
Mi
Do
Fr
Sa
So
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Was viele erwarten: UND
Tag UND Wochentag – so rechnet systemd · 0 Tage
Mo
Di
Mi
Do
Fr
Sa
So
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

Gelber Ring: Tag erfüllt beide Felder.

✅ „Freitag, der 13.“ richtig schreiben
0 0 13 * 5 läuft an jedem 13. und an jedem Freitag. Richtig: 0 0 13 * * plus Test im Befehl, z. B. [ "$(date +\%u)" = 5 ] && befehl – das % muss in der crontab maskiert werden.

🧬cronie, Vixie, BusyBox – die Unterschiede

MerkmalVixie cron (Debian/Ubuntu `cron`, macOS)cronie (Fedora, RHEL, Arch)BusyBox crond (Alpine, Embedded)
ODER-Regelja – „eingeschränkt“ = erstes Zeichen ist nicht *ja – gleiche Codebasis wie Vixieja – aber „eingeschränkt“ = Wertemenge unvollständig (FixDayDow()), */2 zählt als eingeschränkt
Namen in Bereichen/ListenHandbuch: nicht erlaubterlaubt (mon,wed,fri · jan-mar)erlaubt (Parser akzeptiert Namen an beiden Bereichsenden)
Zufall–6~15 (Zufallsminute beim Einlesen), RANDOM_DELAY–
Zeitzone je crontabnein (Debian: LIMITATIONS)CRON_TZ=…nein
PATH im Job (Testlauf)/usr/bin:/bin/usr/bin:/bin:/usr/sbin:/sbinPATH aus der crontab, sonst von crond geerbt
Systemtabellen/etc/crontab, /etc/cron.d/* mit Benutzerfeld/etc/crontab, /etc/cron.d/* mit Benutzerfeldnur /var/spool/cron/crontabs/<user>
ZeitumstellungNachholen/nicht wiederholen für feste Uhrzeiten (cron(8))cron(8) wie Vixie; crontab(5) beschreibt dagegen Auslassen/Doppelnreine Wanduhr: prüft jede echte Minute mit localtime()
Läuft der Job noch?startet trotzdem erneutstartet trotzdem erneutüberspringt die Zeile, solange der letzte Lauf noch läuft
@-Stringsjajaoptional (Build-Option)

Quellen: Handbuchseiten von Debian 13 (cron 3.0pl1-197) und Fedora (cronie 1.7.2), Quelltext miscutils/crond.c von BusyBox; PATH-Werte aus echten Testläufen in Containern mit * * * * * env.

⏱️Sechs Felder mit Sekunden: Quartz, Spring, node-cron

Viele Bibliotheken setzen ein Sekunden-Feld VOR die Minute. Wer so einen Ausdruck in eine crontab kopiert, verschiebt alle Felder um eins.
SystemFelder„Jeden Montag um 04:30“Besonderheiten
crontab (Vixie, cronie, BusyBox)Min Std Tag Mon WT30 4 * * 1keine Sekunden, ODER-Regel
Quartz (Java)Sek Min Std Tag Mon WT [Jahr]0 30 4 ? * MON„?“ in Tag ODER Wochentag Pflicht, L, W, #; Wochentag 1 = Sonntag (1–7)
Spring @ScheduledSek Min Std Tag Mon WT0 30 4 * * MON0 und 7 = Sonntag, L/W/#/? und @daily usw. seit Spring 5.3, zone= für Zeitzone
node-cron[Sek] Min Std Tag Mon WT30 4 * * 1Sekunden optional vorne, Option timezone
BullMQ (Job Scheduler)[Sek] Min Std Tag Mon WT0 30 4 * * 1pattern + tz, benötigt Redis
Kubernetes CronJobMin Std Tag Mon WT30 4 * * 1Zeitzone über .spec.timeZone
GitHub ActionsMin Std Tag Mon WT30 4 * * 1Standard UTC, optional timezone; keine @-Strings; min. alle 5 Minuten
⚠️ Der Editor erkennt es
Tippst du im Editor 0 30 4 * * 1 ein, meldet er „6 Felder – Sekunden vorne sind Quartz/Spring/node-cron-Format“.?, L, W und # werden ebenfalls als Quartz-Syntax erkannt.