Guides 8 min läsning

Cron-uttryck förklarade: syntax, exempel och vanliga misstag

Ett cron-uttryck är fem fält som anger när ett jobb körs. Syntaxen, specialtecknen och genvägar som @daily, färdiga exempel och misstagen med tidszon och PATH som får jobb att sluta fungera.

Ett cron-uttryck består av fem fält åtskilda av mellanslag: minut, timme, dag i månaden, månad och veckodag, följda av kommandot som ska köras. 30 2 * * * betyder ”klockan 02:30 varje dag”. Varje fält tar ett tal, en * för ”alla värden”, en lista med kommatecken, ett intervall med bindestreck eller ett steg med snedstreck. De flesta problem med cron beror inte på själva syntaxen utan på det runt omkring: serverns tidszon, regeln för hur dag i månaden och veckodag kombineras, och den minimala miljö som cron kör kommandon i.

Den här guiden förklarar varje fält och specialtecken, ger en tabell med färdiga uttryck och går igenom misstagen som gör att jobb körs vid fel tid, eller inte alls.

De fem fälten

Varje rad i en användares crontab följer samma upplägg:

┌───────────── minut (0–59)
│ ┌─────────── timme (0–23)
│ │ ┌───────── dag i månaden (1–31)
│ │ │ ┌─────── månad (1–12 eller JAN–DEC)
│ │ │ │ ┌───── veckodag (0–7 eller SUN–SAT, både 0 och 7 är söndag)
│ │ │ │ │
* * * * * /path/to/command

Ett jobb körs när den aktuella minuten matchar alla fält, med ett undantag för de två dagfälten som beskrivs nedan. Månader och veckodagar kan skrivas som engelska namn med tre bokstäver, och det spelar ingen roll om du använder versaler eller gemener.

Du redigerar din egen crontab med crontab -e och listar den med crontab -l. Systemövergripande filer, /etc/crontab och filerna i /etc/cron.d/, har ett sjätte fält mellan schemat och kommandot: användaren som jobbet körs som. Att kopiera en rad från det ena formatet till det andra utan att lägga till eller ta bort det fältet är ett klassiskt sätt att få ett jobb att sluta fungera.

Specialtecken

TeckenBetydelseExempelResultat*Alla värden* * * * *Varje minut,Lista med värden0 8,12,18 * * *Klockan 08:00, 12:00 och 18:00-Intervall0 9 * * 1-509:00 måndag till fredag/Steg*/15 * * * *Minut 0, 15, 30 och 45

Hur steg egentligen fungerar

Ett steg delar upp ett fälts intervall med början i dess första värde. */15 i minutfältet betyder 0, 15, 30 och 45. Ett steg kan också gälla ett intervall: 0-30/10 betyder minut 0, 10, 20 och 30.

Steg börjar om vid fältets gräns. */7 i minutfältet körs vid 0, 7, 14 och så vidare upp till 56, sedan vid 0 igen, så det sista mellanrummet varje timme är bara fyra minuter. */7 är alltså inte ”var sjunde minut”. Klassisk cron kan inte heller uttrycka ”var 90:e minut” på en rad; då behöver du två rader eller en kontroll i skriptet.

Syntax som inte är klassisk cron

I dokumentation kan du stöta på L (sista), W (närmaste vardag), # (n:te veckodagen i månaden) och ?. De kommer från Quartz och vissa schemaläggare i moln- och CI-tjänster, inte från cron på en Linuxserver, och en del av de schemaläggarna lägger också till ett sekundfält först. Många cron-varianter godtar inte heller intervall med namn, så skriv 1-5 i stället för MON-FRI.

Genvägar som @daily

De flesta cron-implementationer på Linux godtar en namngiven genväg i stället för de fem fälten:

@reboot: en gång, när cron-tjänsten startar efter en omstart.

@yearly eller @annually: 0 0 1 1 *, midnatt den 1 januari.

@monthly: 0 0 1 * *, midnatt den första i månaden.

@weekly: 0 0 * * 0, midnatt mellan lördag och söndag.

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

@hourly: 0 * * * *.

Alla genvägar körs på jämna timmen eller vid midnatt, så på en belastad server slåss alla jobb om samma resurser klockan 00:00. Skriver du ut hela uttrycket med en udda minut, till exempel 17 0 * * *, sprids belastningen.

Färdiga cron-uttryck

UttryckKörs* * * * *Varje minut*/5 * * * *Var 5:e minut*/15 * * * *Var 15:e minut0 * * * *Varje timme, på jämna timmen15 */2 * * *Minut 15 varannan timme: 00:15, 02:15, 04:15 och så vidare0 9-17 * * 1-5Varje timme från 09:00 till 17:00, måndag till fredag*/10 8-18 * * 1-5Var 10:e minut under kontorstid på vardagar30 2 * * *Varje dag klockan 02:300 8,12,18 * * *Tre gånger om dagen: 08:00, 12:00 och 18:000 6 * * 1Varje måndag klockan 06:000 22 * * 5Varje fredag klockan 22:000 0 * * 0Varje söndag vid midnatt0 3 1 * *Den första dagen i varje månad klockan 03:000 4 1,15 * *Den 1:a och 15:e i varje månad klockan 04:000 5 1 */3 *Varje kvartal: den 1 januari, april, juli och oktober klockan 05:000 0 1 1 *En gång om året, vid midnatt den 1 januari@rebootEn gång efter varje systemstart

Ett vanligt misstag här är * */2 * * *. Det körs inte varannan timme. Det körs varje minut under varannan timme, sextio gånger i rad. När du begränsar timmen ska du alltid ange minuten också.

Dag i månaden och veckodag: ELLER-regeln

Alla fält kombineras med OCH, utom de två dagfälten. När både dag i månaden och veckodag är begränsade, alltså när inget av dem är *, körs jobbet när något av dem matchar. Den här raden:

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

körs alltså klockan 09:00 den första varje månad och klockan 09:00 varje måndag, inte bara på måndagar som infaller den första. Av samma skäl betyder 0 9 1-7 * 1 inte ”första måndagen i månaden”; den körs dag 1 till 7 och varje måndag. För att få första måndagen schemalägger du dag 1 till 7 och kontrollerar veckodagen i kommandot. Lägg märke till det escapade procenttecknet, som förklaras längre ned:

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

Klassisk cron har inte heller någon ”sista dagen i månaden”. Med GNU date schemalägger du dag 28 till 31 och kör bara när i morgon är den första:

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

Tidszoner och sommartid

Cron använder tidszonen i systemet den körs på. Ett jobb som är skrivet för svensk tid på en server som är inställd på UTC startar en eller två timmar fel, beroende på årstid. Kontrollera serverns tidszon med timedatectl eller date innan du väljer schema. Använd samma tidszon när du övervakar jobbet: cron-övervakningar i Uptimecheck tar crontab-schemat tillsammans med en tidszon, så att de förväntade körtiderna stämmer med serverns.

Vissa implementationer, som cronie, godtar en CRON_TZ-variabel överst i crontab för att köra schemana i en annan tidszon. Stödet skiljer sig mellan cron-versioner, så testa det i stället för att utgå från att det fungerar.

Sommartiden ger de konstigaste buggarna. På våren finns en lokal timme inte; på hösten inträffar en timme två gånger. Ett jobb som är schemalagt ungefär mellan 01:00 och 03:00 lokal tid kan hoppas över, försenas eller köras två gånger, och hur varje cron-implementation hanterar omställningen varierar. De säkraste alternativen:

Kör servrarna på UTC, som saknar sommartid, och räkna om i huvudet eller i en kommentar.

Om servern måste gå på lokal tid, lägg viktiga jobb utanför timmarna när klockan ställs om.

Skriv tidszonen i en kommentar ovanför varje jobb, så att nästa person inte behöver gissa.

Gör jobben säkra att köra två gånger, till exempel genom att kontrollera om dagens export redan finns.

Fällor med miljön och PATH

Ett kommando som fungerar i terminalen men misslyckas i cron misslyckas nästan alltid på grund av miljön. Cron laddar inte din skalprofil, så mycket av det du tar för givet saknas:

PATH är minimal, ofta bara /usr/bin:/bin. Kommandon i /usr/local/bin, eller verktyg installerade med nvm, pyenv, rbenv eller Composer, hittas inte. Använd absoluta sökvägar eller sätt PATH överst i crontab.

Skalet är /bin/sh, inte bash. Syntax som bara finns i bash, som [[ ]] eller source, misslyckas. Sätt SHELL=/bin/bash eller lägg logiken i ett skript med en bash-shebang.

Procenttecken är speciella. På en rad i crontab blir % en radbrytning. date +%F måste skrivas date +\%F, eller flyttas in i ett skript.

Arbetskatalogen är användarens hemkatalog, inte ditt projekt. Relativa sökvägar pekar fel. Gör cd till projektet först.

Miljövariablerna är borta. API-nycklar och databas-URL:er som exporteras i .bashrc finns inte. Läs in dem från en fil i skriptet.

Utdata försvinner. Cron mejlar utdata till MAILTO om e-post är konfigurerad, och på de flesta servrar är den inte det. Styr om utdata till en loggfil.

Körningar kan överlappa. Om ett jobb som körs var femte minut ibland tar sju, körs två kopior samtidigt. flock -n hoppar över en körning medan den förra håller låset.

Vissa cron-versioner ignorerar också en sista rad som inte slutar med en radbrytning. En crontab som hanterar allt detta ser ut så här:

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

# Nightly database backup. Server time is UTC.
30 2 * * * cd /var/www/fjordstudio && flock -n /tmp/backup.lock ./bin/backup.sh >> /var/log/backup.log 2>&1

Så testar du ett cron-uttryck

Läs tillbaka det i ord. Klistra in uttrycket i en tolk för cron-uttryck och kontrollera att beskrivningen och de närmaste körtiderna stämmer med det du menade.

Kör kommandot i crons miljö. En avskalad miljö återskapar de flesta ”det fungerar i min terminal”-fel innan du väntar på schemat.

Schemalägg det varje minut en gång. Använd * * * * * tillfälligt, se att det körs och sätt sedan det riktiga schemat.

Kontrollera att cron startade det. På Debian och Ubuntu: grep CRON /var/log/syslog eller journalctl -u cron; på Red Hat-baserade system: /var/log/cron eller journalctl -u crond.

Bekräfta att crontab är installerad med crontab -l, som den användare som ska köra den.

Så simulerar du crons miljö från ett skal:

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

Ge varje jobb en heartbeat

Ett korrekt uttryck talar bara om för cron när ett jobb ska startas. Det säger ingenting om huruvida jobbet kördes eller blev klart. En omstart, en överskriven crontab eller en saknad variabel misslyckas alla i tysthet.

En heartbeat täpper till det glappet. Jobbet anropar en unik URL när det har slutförts, och övervakningstjänsten larmar dig när anropet inte kommer enligt schemat:

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

Ställ in heartbeatens förväntade intervall efter samma schema som cron-uttrycket, med marginal för långsamma körningar: 24 timmar plus lite extra för ett nattligt jobb, en timme plus lite extra för ett som körs varje timme. Övervakning av cron-jobb i Uptimecheck fungerar så, med larm när en ping uteblir och ett meddelande när jobbet hör av sig igen. Cron-övervakningarna tar crontab-schemat i din tidszon, tar emot start- och slutpingar på samma övervakning, larmar när en körning överskrider sin maximala körtid och kan spara exit code och jobbets utdata. Guiden om hur du övervakar cron-jobb med heartbeats går igenom uppsättningen i detalj, och så undviker du missade cron-jobb tar upp rutinerna runt omkring.

När en heartbeat uteblir ligger orsaken ofta på servern: en full disk, slut på minne eller en oplanerad omstart. Serverövervakning bredvid dina heartbeats visar orsaken i samma stund.

Checklista över vanliga misstag

Att begränsa timmen men lämna minuten som *.

Att ange båda dagfälten och förvänta sig OCH i stället för ELLER.

Att utgå från att servern ligger i din tidszon.

Att schemalägga viktiga jobb under timmen då sommartiden ställs om.

Att använda relativa sökvägar, bash-syntax eller % utan escape.

Att köra ett jobb utan heartbeat, så att ingen märker när det slutar fungera.

Sammanfattning

Fem fält, fyra specialtecken och en handfull genvägar räcker för nästan alla scheman du kommer att behöva. Uttrycket är sällan problemet. Det är tidszoner, ELLER-regeln för dagfälten och crons avskalade miljö. Skriv tidszonen bredvid varje jobb, använd absoluta sökvägar, logga utdata och ge varje jobb som spelar roll en heartbeat.

Heartbeats i Uptimecheck ingår i alla planer, även Free, tillsammans med övervakning av upptid, SSL, domäner och DNS. Starta en gratis provperiod på 14 dagar, inget kreditkort krävs.

Frågor

Vad betyder */5 * * * * i cron?

Var femte minut: vid minut 0, 5, 10 och så vidare till och med 55 varje timme, varje dag.

Hur kör jag ett cron-jobb varannan timme?

Använd 0 */2 * * *, som körs vid minut 0 varannan timme. Skriver du * */2 * * * körs jobbet i stället varje minut under varannan timme.

Vilken tidszon använder cron?

Tidszonen i systemet den körs på. Många molnservrar och containrar använder UTC, så kontrollera med timedatectl eller date innan du väljer schema. Vissa implementationer stöder en CRON_TZ-variabel.

Varför fungerar mitt cron-jobb i terminalen men inte i cron?

Cron kör kommandon med en minimal PATH, /bin/sh som skal, hemkatalogen som arbetskatalog och utan din skalprofil. Använd absoluta sökvägar, escapa %-tecken och logga utdata för att se felet.

Läs vidare

Guides 6 min läsning

Så övervakar du cron-jobb med heartbeats

Cron-jobb misslyckas i tysthet. En heartbeat-monitor larmar när ett schemalagt jobb inte hör av sig i tid. Så fungerar heartbeats, så lägger du till en i crontab och så väljer du rätt inställningar.

Läs

Driftstopp är historia.

Sätt upp din första övervakning på under en minut, eller ta en titt i livedemon först.

14 dagar gratis · Sedan gratis för 5 övervakningar · Inget kreditkort