Auf einer modernen Distribution gilt: für alles, was dir gehört, ein systemd-Timer — cron bleibt für Einzeiler-Jobs und Server, die nicht du aufgesetzt hast. Timer loggen jeden Lauf ins Journal, holen Zeitpläne nach, die verpasst wurden, während die Maschine aus war, und hängen an denselben Unit-Dateien wie alles andere im System. Cron punktet mit Kürze — eine crontab -e-Zeile schlägt zwei Unit-Dateien — und ist noch immer der einzige Scheduler, der auf minimalen Containern und exotischen Unix-Kisten garantiert existiert. Der Haken: Cron versagt lautlos. Irriert dein Job um 3 Uhr nachts, schickt cron eine Mail in ein lokales Postfach, das niemand liest; ein Timer gibt dir journalctl -u mytimer.service mit der vollen Ausgabe. Unten: die echten Unterschiede, wie man beide testet, warum ein Timer nicht triggert, und eine Entscheidungstabelle.
Wo ist der Unterschied zwischen cron und einem systemd-Timer?
Cron ist ein Daemon, der eine Tabelle aus Zeilen liest — fünf Zeitfelder und ein Befehl — und jeden Befehl ausführt, wenn die Wanduhr passt. Das ist das ganze Modell. Es kennt keinen Job als Objekt: keine Unit, kein Status, keine Abhängigkeiten, keinen eigenen Log-Eintrag.
Ein systemd-Timer ist eine Unit-Datei (foo.timer), die eine andere Unit-Datei (foo.service) auslöst, wenn ihr Zeitplan passt. Der Job ist ein Objekt erster Klasse mit start, status, logs und Failure-Tracking wie jeder andere Service. Der Zeitplan ist entweder Kalender-basiert (cron-artig) oder monoton (OnBootSec=15min, was Uhrenänderungen nicht verwirren können).
Die praktischen Folgen:
- Logging: Timer loggen stdout/stderr pro Unit ins Journal; cron schickt allenfalls Mail an den lokalen Nutzer.
- Verpasste Läufe: Ein Timer mit
Persistent=trueholt beim Boot einmal nach, wenn sein Zeitplan verpasst wurde; cron überspringt einfach. - Abhängigkeiten: Timer können auf
network-online.targetoder Mount-Points warten; cron verlangt handgestrickte Retry-Logik im Skript. - Syntax: cron ist eine Zeile; ein Timer sind zwei Dateien. Das sind die gesamten Umstellungskosten.
Welche Syntax ist einfacher — crontab oder OnCalendar?
Crons fünf Felder sind der kompakte Alteingesessene: */15 * * * * heißt alle 15 Minuten, und die meisten Admins lesen sie im Schlaf. systemds OnCalendar= ist gesprächiger, aber streng ausdrucksstärker, und systemd-analyze calendar verrät dir die nächsten Läufe, bevor du speicherst — cron hat kein Dry-Run-Äquivalent.
# Cron: jeden Tag um 03:30
30 3 * * * /usr/local/bin/backup.sh
# systemd: derselbe Zeitplan, vor dem Speichern prüfbar
systemd-analyze calendar "*-*-* 03:30:00"
# -> Nächster Lauf: Fr 2026-09-11 03:30:00 ... OnCalendar kann Dinge, die cron ehrlich nicht sauber ausdrücken kann: Mon..Fri *-*-* 09..17:00:00 (werktags, Geschäftszeiten) oder *:0/15 mit RandomizedDelaySec=10m, damit tausend Maschinen nicht im selben Augenblick auf einen Server einprügeln.
Wie teste ich einen systemd-Timer ohne Wartezeit?
Drei Befehle beantworten alles. Auflisten, was geplant ist und wann es als Nächstes feuert, den Job von Hand genau so laufen lassen, wie es der Timer täte, dann die Logs lesen:
systemctl list-timers --all # jeder Timer, nächster + letzter Lauf
sudo systemctl start backup.service # den Job jetzt feuern, dieselbe Unit wie der Timer
journalctl -u backup.service -f # die Ausgabe live verfolgen Beachte die Trennung: systemctl start backup.timer scharfst den Zeitplan; der Service ist der Job. Zeigt list-timers deinen Timer, ist systemctl status backup.service grün und das Journal zeigt deine Ausgabe, funktioniert die ganze Kette.
Wie führe ich einen cron-Job manuell aus?
Cron-Jobs laufen mit abgemagerter Umgebung — deshalb ist „läuft in meiner Shell, scheitert in cron” eine eigene Fehlergattung. Um cron treu zu reproduzieren, führe den Befehl durch sh mit derselben Umgebung aus, die cron nutzen würde:
crontab -l # die exakte Zeile prüfen
env -i SHELL=/bin/sh PATH=/usr/bin:/bin sh -c '/usr/local/bin/backup.sh'
grep CRON /var/log/syslog | tail # hat cron ihn überhaupt gefeuert? (Debian/Ubuntu)
journalctl -u cron -n 20 # dasselbe, auf systemd-Distros Diese env -i-Zeile ist der ehrliche manuelle Test: nackte Umgebung mit crons Default-PATH. Die meisten stillen cron-Ausfälle sind ein kahler PATH oder ein nicht quotiertes % im Befehl (cron liest % als Zeilenumbruch) — beides zeigt sich so sofort.
Warum triggert mein systemd-Timer nicht?
Vier Ursachen decken fast jeden Fall ab, in dieser Prüf-Reihenfolge:
- Service- und Timer-Name passen nicht zusammen.
foo.timerfeuertfoo.service— ein vertipptesOnFailureoder eine umbenannte Unit bedeutet, der Timer „läuft” ins Leere.systemctl cat foo.timerzeigt exakt, worauf er zielt. - Der Timer wurde editiert, aber nicht neu geladen. Nach einer Änderung an der Unit-Datei:
sudo systemctl daemon-reload && sudo systemctl restart foo.timer. Ohne das ist dein neuer Zeitplan nicht scharf. Persistent=trueohne dieOnCalendar-Semantik, die du erwartest — oder du schaust aufsystemctl status foo.timer(zeigt immer active, auch wenn idle) statt auflist-timers.- Der ausgelöste Service scheitert sofort, deshalb wirkt der Timer tot.
journalctl -u foo.service --since -1hzeigt den Crash, denlist-timersverschweigt.
Und wenn du in den Logs wühlst: Das journalctl cheat sheet deckt die Filter (-u, --since, -f) ab, die das schnell machen.
Cron vs. systemd-Timer: die Entscheidungstabelle
| cron | systemd-Timer | |
|---|---|---|
| Setup | eine crontab-Zeile | zwei Unit-Dateien |
| Logging | lokale Mail, meist ungelesen | Journal, pro Unit |
| Verpasster Lauf (Maschine aus) | übersprungen | holt einmal nach mit Persistent=true |
| Abhängigkeiten / Reihenfolge | keine — DIY im Skript | volle Unit-Abhängigkeiten |
| Zufällige Verzögerung | DIY mit $RANDOM | RandomizedDelaySec= |
| Zeitplan testen / Dry-Run | nein | systemd-analyze calendar |
| Überall vorhanden | ja — Container, BSDs, Embedded | braucht systemd (PID 1) |
| Nutzer-Jobs ohne root | crontab -e | systemd --user-Units |
Faustregeln: Einen Job auf deiner eigenen systemd-Maschine ausliefern → Timer. Schnelle persönliche Erinnerung oder eine Kiste, die du nicht gebaut hast → cron. Alles mit Abhängigkeiten, Retries oder dem Bedürfnis zu wissen, ob es überhaupt lief → immer Timer. Ein verbreitetes Muster ist ein Timer, der einen Wartungsjob fährt — etwa ein nächtliches rsync backup — wobei Persistent=true garantiert, dass das Backup passiert, selbst wenn die Maschine zur geplanten Minute schlief; das kann cron schlicht nicht bieten.
— mrsaynothing
Get the next one by email
One email per post. No spam, no algorithms.
what is this?llama.cpp vs. Ollama: Was solltest du 2026 nutzen?
Sie mögen die Artikel? Genau so baue ich beruflich. anheuern