Guides 8 min. læsning

Cron-udtryk forklaret: syntaks, eksempler og typiske fejl

Et cron-udtryk er fem felter, der angiver, hvornår et job kører. Syntaksen, specialtegn og genveje som @daily, færdige eksempler og de fejl med tidszone og PATH, der får jobs til at fejle.

Et cron-udtryk består af fem felter adskilt af mellemrum: minut, time, dag i måneden, måned og ugedag, efterfulgt af den kommando, der skal køres. 30 2 * * * betyder “kl. 02:30 hver dag”. Hvert felt tager et tal, en * for “alle værdier”, en liste med kommaer, et interval med bindestreg eller et trin med skråstreg. De fleste cron-problemer skyldes ikke selve syntaksen, men det, der omgiver den: serverens tidszone, reglen for, hvordan dag i måneden og ugedag kombineres, og det minimale miljø, cron kører kommandoer i.

Denne guide forklarer hvert felt og hvert specialtegn, giver dig en tabel med færdige udtryk og gennemgår de fejl, der får jobs til at køre på det forkerte tidspunkt eller slet ikke.

De fem felter

Hver linje i en brugers crontab følger samme opbygning:

┌───────────── minut (0–59)
│ ┌─────────── time (0–23)
│ │ ┌───────── dag i måneden (1–31)
│ │ │ ┌─────── måned (1–12 eller JAN–DEC)
│ │ │ │ ┌───── ugedag (0–7 eller SUN–SAT, både 0 og 7 er søndag)
│ │ │ │ │
* * * * * /path/to/command

Et job kører, når det aktuelle minut matcher alle felterne, med én undtagelse for de to dagfelter, som vi gennemgår nedenfor. Måneder og ugedage kan skrives som engelske navne på tre bogstaver, og der skelnes ikke mellem store og små bogstaver.

Du redigerer din egen crontab med crontab -e og viser den med crontab -l. Systemfilerne, /etc/crontab og filerne i /etc/cron.d/, har et sjette felt mellem tidsplanen og kommandoen: den bruger, jobbet kører som. At kopiere en linje fra det ene format til det andet uden at tilføje eller fjerne det felt er en klassisk måde at ødelægge et job på.

Specialtegn

TegnBetydningEksempelResultat*Alle værdier* * * * *Hvert minut,Liste af værdier0 8,12,18 * * *Kl. 08:00, 12:00 og 18:00-Interval0 9 * * 1-5Kl. 09:00 mandag til fredag/Trin*/15 * * * *Minut 0, 15, 30 og 45

Sådan virker trin i virkeligheden

Et trin deler et felts interval op, startende fra dets første værdi. */15 i minutfeltet betyder 0, 15, 30 og 45. Et trin kan også bruges på et interval: 0-30/10 betyder minut 0, 10, 20 og 30.

Trin starter forfra ved feltets grænse. */7 i minutfeltet kører ved 0, 7, 14 og så videre op til 56 og derefter ved 0 igen, så det sidste mellemrum i hver time kun er fire minutter. */7 er altså ikke “hvert syvende minut”. Klassisk cron kan heller ikke udtrykke “hvert 90. minut” på én linje; det kræver to linjer eller et tjek inde i scriptet.

Syntaks, der ikke er klassisk cron

Du støder måske på L (sidste), W (nærmeste hverdag), # (n’te ugedag i måneden) og ? i dokumentation. De stammer fra Quartz og visse cloud- og CI-schedulere, ikke fra cron på en Linux-server, og nogle af de schedulere tilføjer også et sekundfelt i starten. Mange cron-versioner afviser desuden intervaller af navne, så skriv 1-5 i stedet for MON-FRI.

Genveje som @daily

De fleste cron-implementeringer på Linux accepterer en navngivet genvej i stedet for de fem felter:

@reboot: én gang, når cron-dæmonen starter efter en genstart.

@yearly eller @annually: 0 0 1 1 *, midnat den 1. januar.

@monthly: 0 0 1 * *, midnat den første i måneden.

@weekly: 0 0 * * 0, midnat mellem lørdag og søndag.

@daily eller @midnight: 0 0 * * *.

@hourly: 0 * * * *.

Alle genveje udløses på hele timer eller ved midnat, så på en travl server kæmper alle jobs om de samme ressourcer kl. 00:00. Skriver du det fulde udtryk med et skævt minuttal, fx 17 0 * * *, fordeler du belastningen.

Færdige cron-udtryk

UdtrykKører* * * * *Hvert minut*/5 * * * *Hvert 5. minut*/15 * * * *Hvert 15. minut0 * * * *Hver time, på slaget15 */2 * * *Minut 15 hver anden time: 00:15, 02:15, 04:15 og så videre0 9-17 * * 1-5Hver time fra 09:00 til 17:00, mandag til fredag*/10 8-18 * * 1-5Hvert 10. minut i kontortiden på hverdage30 2 * * *Hver dag kl. 02:300 8,12,18 * * *Tre gange om dagen: 08:00, 12:00 og 18:000 6 * * 1Hver mandag kl. 06:000 22 * * 5Hver fredag kl. 22:000 0 * * 0Hver søndag ved midnat0 3 1 * *Den første dag i hver måned kl. 03:000 4 1,15 * *Den 1. og 15. i hver måned kl. 04:000 5 1 */3 *Hvert kvartal: 1. januar, april, juli og oktober kl. 05:000 0 1 1 *Én gang om året, ved midnat den 1. januar@rebootÉn gang efter hver systemstart

En typisk fejl i forhold til listen her er * */2 * * *. Den kører ikke hver anden time. Den kører hvert minut i hver anden time, tres gange i træk. Når du begrænser timen, skal du altid også angive minuttet.

Dag i måneden og ugedag: ELLER-reglen

Alle felter kombineres med OG, undtagen de to dagfelter. Når både dag i måneden og ugedag er begrænset, altså ingen af dem er *, kører jobbet, når ét af dem matcher. Så denne linje:

0 9 1 * 1 /usr/local/bin/report.sh

kører kl. 09:00 den første i hver måned og kl. 09:00 hver mandag, ikke kun på mandage, der falder den første. Af samme grund betyder 0 9 1-7 * 1 ikke “den første mandag i måneden”; den kører på dag 1 til 7 og hver mandag. Vil du have den første mandag, så planlæg dag 1 til 7 og tjek ugedagen i kommandoen. Bemærk det escapede procenttegn, som forklares længere nede:

0 9 1-7 * * [ “$(date +\%u)” = “1” ] && /usr/local/bin/report.sh

Klassisk cron har heller ingen “sidste dag i måneden”. Med GNU date planlægger du dag 28 til 31 og kører kun, når i morgen er den første:

0 23 28-31 * * [ “$(date -d tomorrow +\%d)” = “01” ] && /usr/local/bin/month-end.sh

Tidszoner og sommertid

Cron bruger tidszonen på det system, den kører på. Et job skrevet til Stockholm-tid på en server, der er sat til UTC, starter en eller to timer forkert afhængigt af årstiden. Tjek serverens tidszone med timedatectl eller date, før du vælger en tidsplan. Brug samme tidszone, når du overvåger jobbet: Uptimechecks cron-monitorer tager crontab-tidsplanen sammen med en tidszone, så de forventede kørselstidspunkter passer med serverens.

Nogle implementeringer, fx cronie, accepterer en CRON_TZ-variabel øverst i crontabben, så tidsplanerne kører i en anden tidszone. Understøttelsen varierer mellem cron-versioner, så test det i stedet for at gå ud fra, at det virker.

Sommertid giver de mærkeligste fejl. Om foråret findes én lokal time ikke; om efteråret sker én time to gange. Et job planlagt cirka mellem 01:00 og 03:00 lokal tid kan blive sprunget over, forsinket eller køre to gange, og hvordan hver cron-implementering håndterer skiftet, varierer. De sikreste løsninger:

Kør servere på UTC, som ikke har sommertid, og omregn i hovedet eller i en kommentar.

Skal serveren køre på lokal tid, så hold vigtige jobs uden for de timer, hvor uret stilles.

Skriv tidszonen i en kommentar over hvert job, så den næste ikke skal gætte.

Gør jobs sikre at køre to gange, fx ved at tjekke, om dagens eksport allerede findes.

Faldgruber med miljø og PATH

En kommando, der virker i din terminal, men fejler under cron, fejler næsten altid på grund af miljøet. Cron indlæser ikke din shell-profil, så meget af det, du tager for givet, mangler:

PATH er minimal, ofte kun /usr/bin:/bin. Kommandoer i /usr/local/bin eller værktøjer installeret med nvm, pyenv, rbenv eller Composer bliver ikke fundet. Brug absolutte stier, eller sæt PATH øverst i crontabben.

Shellen er /bin/sh, ikke bash. Syntaks, der kun findes i bash, som [[ ]] eller source, fejler. Sæt SHELL=/bin/bash, eller læg logikken i et script med en bash-shebang.

Procenttegn er specielle. I en crontab-linje bliver % til et linjeskift. date +%F skal skrives date +\%F eller flyttes ind i et script.

Arbejdsmappen er brugerens hjemmemappe, ikke dit projekt. Relative stier peger det forkerte sted hen. Brug cd til projektet først.

Miljøvariabler er væk. API-nøgler og database-URL’er, der eksporteres i .bashrc, findes ikke. Indlæs dem fra en fil i scriptet.

Output forsvinder. Cron mailer output til MAILTO, hvis mail er sat op, og det er det ikke på de fleste servere. Send output til en logfil.

Kørsler kan overlappe. Hvis et job, der kører hvert femte minut, nogle gange tager syv, kører to kopier samtidig. flock -n springer en kørsel over, så længe den forrige holder låsen.

Nogle cron-versioner ignorerer også en sidste linje, der ikke slutter med et linjeskift. En crontab, der tager højde for alt dette, ser sådan ud:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=””

# Natlig databasebackup. Servertiden er UTC.
30 2 * * * cd /var/www/fjordstudio && flock -n /tmp/backup.lock ./bin/backup.sh >> /var/log/backup.log 2>&1

Sådan tester du et cron-udtryk

Læs det tilbage med ord. Indsæt udtrykket i en cron-parser, og tjek, at beskrivelsen og de næste kørselstidspunkter svarer til det, du mente.

Kør kommandoen i crons miljø. Et nedskåret miljø genskaber de fleste “det virker i min terminal”-fejl, før du venter på tidsplanen.

Planlæg det til hvert minut én gang. Brug * * * * * midlertidigt, se det køre, og sæt derefter den rigtige tidsplan.

Tjek, at cron startede det. På Debian og Ubuntu: grep CRON /var/log/syslog eller journalctl -u cron; på Red Hat-baserede systemer: /var/log/cron eller journalctl -u crond.

Bekræft, at crontabben er installeret med crontab -l som den bruger, der skal køre den.

Sådan simulerer du crons miljø fra en shell:

env -i SHELL=/bin/sh PATH=/usr/bin:/bin HOME=”$HOME” /bin/sh -c ‘/usr/local/bin/backup.sh’

Giv hvert job et heartbeat

Et korrekt udtryk fortæller kun cron, hvornår et job skal starte. Det siger intet om, hvorvidt jobbet kørte eller blev færdigt. En genstart, en overskrevet crontab eller en manglende variabel fejler alle i stilhed.

Et heartbeat lukker det hul. Jobbet kalder en unik URL, når det er færdigt uden fejl, og overvågningstjenesten giver dig en alarm, når kaldet ikke kommer til tiden:

30 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 –retry 3 https://heartbeat.example.com/your-unique-id > /dev/null

Sæt heartbeatets forventede interval til samme tidsplan som cron-udtrykket, med margen til langsomme kørsler: 24 timer plus lidt for et natligt job, én time plus lidt for et job, der kører hver time. Uptimechecks overvågning af cron-jobs virker på den måde, med alarmer, når et ping mangler, og en besked, når jobbet melder sig igen. Cron-monitorerne tager crontab-tidsplanen i din tidszone, accepterer start- og slutping på én monitor, giver alarm, når en kørsel overskrider sin maksimale kørselstid, og kan gemme exitkoden og jobbets output. Guiden om at overvåge cron-jobs med heartbeats gennemgår opsætningen i detaljer, og at undgå oversprungne cron-opgaver handler om vanerne omkring det.

Når et heartbeat udebliver, ligger årsagen ofte på serveren: en fuld disk, opbrugt hukommelse eller en uplanlagt genstart. Serverovervågning ved siden af dine heartbeats viser årsagen i samme øjeblik.

Tjekliste over typiske fejl

At begrænse timen, men lade minuttet stå som *.

At sætte begge dagfelter og forvente OG i stedet for ELLER.

At gå ud fra, at serveren er i din tidszone.

At planlægge vigtige jobs i sommertidstimen.

At bruge relative stier, bash-syntaks eller % uden escape.

At køre et job uden heartbeat, så ingen opdager det, når det stopper.

Opsummering

Fem felter, fire specialtegn og en håndfuld genveje dækker næsten enhver tidsplan, du får brug for. Udtrykket er sjældent problemet. Det er tidszoner, ELLER-reglen for dagfelterne og crons nøgne miljø. Skriv tidszonen ved hvert job, brug absolutte stier, log outputtet, og giv hvert job, der betyder noget, et heartbeat.

Uptimechecks heartbeats er med i alle planer, også Free, sammen med oppetids-, SSL-, domæne- og DNS-overvågning. Start en gratis prøveperiode på 14 dage, uden kreditkort.

Spørgsmål

Hvad betyder */5 * * * * i cron?

Hvert femte minut: ved minut 0, 5, 10 og så videre til og med 55 i hver time, hver dag.

Hvordan kører jeg et cron-job hver anden time?

Brug 0 */2 * * *, som kører ved minut 0 hver anden time. Skriver du * */2 * * *, kører det i stedet hvert minut i hver anden time.

Hvilken tidszone bruger cron?

Tidszonen på det system, den kører på. Mange cloudservere og containere bruger UTC, så tjek med timedatectl eller date, før du vælger en tidsplan. Nogle implementeringer understøtter en CRON_TZ-variabel.

Hvorfor virker mit cron-job i terminalen, men ikke i cron?

Cron kører kommandoer med en minimal PATH, /bin/sh som shell, hjemmemappen som arbejdsmappe og uden din shell-profil. Brug absolutte stier, escape %-tegn, og log outputtet for at se fejlen.

Læs videre

Guides 6 min. læsning

Sådan overvåger du cron-jobs med heartbeats

Cron-jobs fejler i stilhed. En heartbeat-monitor giver dig en alarm, når et planlagt job ikke melder sig til tiden. Sådan virker heartbeats, sådan tilføjer du en til en crontab, og de indstillinger, du skal vælge.

Læs

Nedetid er fortid.

Opret din første monitor på under et minut, eller se dig omkring i livedemoen først.

14 dages gratis prøveperiode · Derefter gratis med 5 monitorer · Intet betalingskort