🔤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
| # | Feld | Werte | Namen |
|---|---|---|---|
| 1 | Minute | 0–59 | – |
| 2 | Stunde | 0–23 | – |
| 3 | Tag des Monats | 1–31 | – |
| 4 | Monat | 1–12 | jan … dec |
| 5 | Wochentag | 0–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".
⚠️ „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
| String | entspricht | Bedeutung |
|---|---|---|
| @reboot | – | einmal beim Start des cron-Daemons |
| @yearly | 0 0 1 1 * | einmal im Jahr |
| @annually | 0 0 1 1 * | einmal im Jahr (wie @yearly) |
| @monthly | 0 0 1 * * | einmal im Monat |
| @weekly | 0 0 * * 0 | einmal pro Woche |
| @daily | 0 0 * * * | einmal am Tag |
| @midnight | 0 0 * * * | einmal am Tag (wie @daily) |
| @hourly | 0 * * * * | 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.
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.
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
| Merkmal | Vixie cron (Debian/Ubuntu `cron`, macOS) | cronie (Fedora, RHEL, Arch) | BusyBox crond (Alpine, Embedded) |
|---|---|---|---|
| ODER-Regel | ja – „eingeschränkt“ = erstes Zeichen ist nicht * | ja – gleiche Codebasis wie Vixie | ja – aber „eingeschränkt“ = Wertemenge unvollständig (FixDayDow()), */2 zählt als eingeschränkt |
| Namen in Bereichen/Listen | Handbuch: nicht erlaubt | erlaubt (mon,wed,fri · jan-mar) | erlaubt (Parser akzeptiert Namen an beiden Bereichsenden) |
| Zufall | – | 6~15 (Zufallsminute beim Einlesen), RANDOM_DELAY | – |
| Zeitzone je crontab | nein (Debian: LIMITATIONS) | CRON_TZ=… | nein |
| PATH im Job (Testlauf) | /usr/bin:/bin | /usr/bin:/bin:/usr/sbin:/sbin | PATH aus der crontab, sonst von crond geerbt |
| Systemtabellen | /etc/crontab, /etc/cron.d/* mit Benutzerfeld | /etc/crontab, /etc/cron.d/* mit Benutzerfeld | nur /var/spool/cron/crontabs/<user> |
| Zeitumstellung | Nachholen/nicht wiederholen für feste Uhrzeiten (cron(8)) | cron(8) wie Vixie; crontab(5) beschreibt dagegen Auslassen/Doppeln | reine Wanduhr: prüft jede echte Minute mit localtime() |
| Läuft der Job noch? | startet trotzdem erneut | startet trotzdem erneut | überspringt die Zeile, solange der letzte Lauf noch läuft |
| @-Strings | ja | ja | optional (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.
| System | Felder | „Jeden Montag um 04:30“ | Besonderheiten |
|---|---|---|---|
| crontab (Vixie, cronie, BusyBox) | Min Std Tag Mon WT | 30 4 * * 1 | keine 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 @Scheduled | Sek Min Std Tag Mon WT | 0 30 4 * * MON | 0 und 7 = Sonntag, L/W/#/? und @daily usw. seit Spring 5.3, zone= für Zeitzone |
| node-cron | [Sek] Min Std Tag Mon WT | 30 4 * * 1 | Sekunden optional vorne, Option timezone |
| BullMQ (Job Scheduler) | [Sek] Min Std Tag Mon WT | 0 30 4 * * 1 | pattern + tz, benötigt Redis |
| Kubernetes CronJob | Min Std Tag Mon WT | 30 4 * * 1 | Zeitzone über .spec.timeZone |
| GitHub Actions | Min Std Tag Mon WT | 30 4 * * 1 | Standard 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.