Guides 8 min di lettura

Espressioni cron spiegate: sintassi, esempi ed errori comuni

Un'espressione cron è composta da cinque campi che dicono quando viene eseguito un job. La sintassi, i caratteri speciali e le scorciatoie come @daily, esempi pronti all'uso e gli errori di fuso orario e PATH che rompono i job.

Un’espressione cron è composta da cinque campi separati da spazi: minuto, ora, giorno del mese, mese e giorno della settimana, seguiti dal comando da eseguire. 30 2 * * * significa “alle 02:30 ogni giorno”. Ogni campo accetta un numero, un * per “qualsiasi valore”, un elenco con le virgole, un intervallo con il trattino o un passo con la barra. La maggior parte dei problemi con cron non nasce dalla sintassi in sé, ma da ciò che le sta intorno: il fuso orario del server, la regola con cui si combinano giorno del mese e giorno della settimana e l’ambiente minimo in cui cron esegue i comandi.

Questa guida spiega ogni campo e ogni carattere speciale, offre una tabella di espressioni pronte all’uso e passa in rassegna gli errori che fanno partire i job all’orario sbagliato, o non li fanno partire affatto.

I cinque campi

Ogni riga di un crontab utente segue lo stesso schema:

┌───────────── minute (0–59)
│ ┌─────────── hour (0–23)
│ │ ┌───────── day of month (1–31)
│ │ │ ┌─────── month (1–12 or JAN–DEC)
│ │ │ │ ┌───── day of week (0–7 or SUN–SAT, 0 and 7 are both Sunday)
│ │ │ │ │
* * * * * /path/to/command

Un job viene eseguito quando il minuto corrente corrisponde a tutti i campi, con un’eccezione per i due campi dei giorni, spiegata più avanti. Mesi e giorni della settimana si possono scrivere con le tre lettere iniziali del nome inglese, senza distinzione tra maiuscole e minuscole.

Il tuo crontab si modifica con crontab -e e si visualizza con crontab -l. I file di sistema, /etc/crontab e quelli in /etc/cron.d/, hanno un sesto campo tra la pianificazione e il comando: l’utente con cui gira il job. Copiare una riga da un formato all’altro senza aggiungere o togliere quel campo è un modo classico per rompere un job.

Caratteri speciali

CarattereSignificatoEsempioRisultato*Qualsiasi valore* * * * *Ogni minuto,Elenco di valori0 8,12,18 * * *Alle 08:00, alle 12:00 e alle 18:00-Intervallo0 9 * * 1-5Alle 09:00 dal lunedì al venerdì/Passo*/15 * * * *Ai minuti 0, 15, 30 e 45

Come funzionano davvero i passi

Un passo suddivide l’intervallo di un campo a partire dal suo primo valore. */15 nel campo dei minuti significa 0, 15, 30 e 45. Un passo si può applicare anche a un intervallo: 0-30/10 significa i minuti 0, 10, 20 e 30.

I passi ripartono al limite del campo. */7 nel campo dei minuti scatta a 0, 7, 14 e così via fino a 56, poi di nuovo a 0, quindi l’ultimo intervallo di ogni ora è di soli quattro minuti. */7 non significa “ogni sette minuti”. Il cron classico non riesce nemmeno a esprimere “ogni 90 minuti” in una sola riga: servono due righe o un controllo all’interno dello script.

Sintassi che non è cron classico

Nella documentazione potresti trovare L (ultimo), W (giorno feriale più vicino), # (n-esimo giorno della settimana del mese) e ?. Arrivano da Quartz e da alcuni scheduler cloud e CI, non dal cron di un server Linux, e alcuni di questi scheduler aggiungono anche un campo dei secondi all’inizio. Molte versioni di cron rifiutano anche gli intervalli di nomi, quindi scrivi 1-5 invece di MON-FRI.

Scorciatoie come @daily

La maggior parte delle implementazioni di cron su Linux accetta una scorciatoia con nome al posto dei cinque campi:

@reboot: una volta, quando il demone cron si avvia dopo un riavvio.

@yearly o @annually: 0 0 1 1 *, mezzanotte del 1° gennaio.

@monthly: 0 0 1 * *, mezzanotte del primo giorno del mese.

@weekly: 0 0 * * 0, la mezzanotte tra sabato e domenica.

@daily o @midnight: 0 0 * * *.

@hourly: 0 * * * *.

Tutte le scorciatoie scattano allo scoccare dell’ora o a mezzanotte, quindi su un server molto carico tutti i job si contendono le stesse risorse alle 00:00. Scrivere l’espressione completa con un minuto insolito, come 17 0 * * *, distribuisce il carico.

Espressioni cron pronte all’uso

EspressioneEsecuzione* * * * *Ogni minuto*/5 * * * *Ogni 5 minuti*/15 * * * *Ogni 15 minuti0 * * * *Ogni ora, allo scoccare dell’ora15 */2 * * *Al minuto 15 di un’ora sì e una no: 00:15, 02:15, 04:15 e così via0 9-17 * * 1-5Ogni ora dalle 09:00 alle 17:00, dal lunedì al venerdì*/10 8-18 * * 1-5Ogni 10 minuti in orario d’ufficio nei giorni feriali30 2 * * *Ogni giorno alle 02:300 8,12,18 * * *Tre volte al giorno: 08:00, 12:00 e 18:000 6 * * 1Ogni lunedì alle 06:000 22 * * 5Ogni venerdì alle 22:000 0 * * 0Ogni domenica a mezzanotte0 3 1 * *Il primo giorno di ogni mese alle 03:000 4 1,15 * *Il 1° e il 15 di ogni mese alle 04:000 5 1 */3 *Ogni trimestre: 1° gennaio, aprile, luglio e ottobre alle 05:000 0 1 1 *Una volta all’anno, a mezzanotte del 1° gennaio@rebootUna volta dopo ogni avvio del sistema

Un errore frequente rispetto a questo elenco è * */2 * * *. Non viene eseguito ogni due ore: viene eseguito ogni minuto durante un’ora sì e una no, sessanta volte di fila. Quando limiti l’ora, imposta sempre anche il minuto.

Giorno del mese e giorno della settimana: la regola OR

Tutti i campi si combinano in AND, tranne i due campi dei giorni. Quando sono limitati sia il giorno del mese sia il giorno della settimana, cioè nessuno dei due è *, il job viene eseguito quando corrisponde uno dei due. Quindi questa riga:

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

viene eseguita alle 09:00 del primo di ogni mese e alle 09:00 di ogni lunedì, non solo nei lunedì che cadono il primo del mese. Per lo stesso motivo, 0 9 1-7 * 1 non significa “il primo lunedì del mese”: viene eseguita dal giorno 1 al giorno 7 e in ogni lunedì. Per ottenere il primo lunedì, pianifica i giorni dall’1 al 7 e controlla il giorno della settimana nel comando. Nota il segno di percentuale con escape, spiegato più avanti:

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

Il cron classico non ha nemmeno un “ultimo giorno del mese”. Con GNU date, pianifica i giorni dal 28 al 31 ed esegui solo quando domani è il primo:

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

Fusi orari e ora legale

Cron usa il fuso orario del sistema su cui gira. Un job scritto per l’ora di Stoccolma su un server impostato in UTC parte con un’ora o due di scarto, a seconda della stagione. Controlla il fuso del server con timedatectl o date prima di scegliere una pianificazione. Usa lo stesso fuso quando monitori il job: i monitor cron di Uptimecheck accettano la pianificazione del crontab insieme a un fuso orario, così gli orari di esecuzione attesi coincidono con quelli del server.

Alcune implementazioni, come cronie, accettano una variabile CRON_TZ in cima al crontab per eseguire le pianificazioni in un altro fuso. Il supporto varia tra le versioni di cron, quindi provala invece di dare per scontato che funzioni.

L’ora legale provoca i bug più strani. In primavera un’ora locale non esiste; in autunno la stessa ora si ripete due volte. Un job pianificato all’incirca tra le 01:00 e le 03:00 ora locale può essere saltato, ritardato o eseguito due volte, e il modo in cui ogni implementazione di cron gestisce il cambio d’ora varia. Le soluzioni più sicure:

Fai girare i server in UTC, che non ha ora legale, e fai la conversione a mente o in un commento.

Se il server deve usare l’ora locale, tieni i job importanti fuori dalle ore in cui cambia l’orologio.

Scrivi il fuso orario in un commento sopra ogni job, così chi viene dopo non deve indovinarlo.

Rendi i job sicuri da eseguire due volte, per esempio controllando se l’export di oggi esiste già.

Insidie di ambiente e PATH

Un comando che funziona nel terminale e fallisce con cron fallisce quasi sempre per colpa dell’ambiente. Cron non carica il profilo della tua shell, quindi manca molto di ciò che dai per scontato:

Il PATH è minimo, spesso solo /usr/bin:/bin. I comandi in /usr/local/bin, o gli strumenti installati con nvm, pyenv, rbenv o Composer, non vengono trovati. Usa percorsi assoluti o imposta PATH in cima al crontab.

La shell è /bin/sh, non bash. La sintassi solo bash, come [[ ]] o source, fallisce. Imposta SHELL=/bin/bash oppure metti la logica in uno script con lo shebang di bash.

Il segno di percentuale è speciale. In una riga del crontab, % diventa un a capo. date +%F va scritto date +\%F, oppure spostato in uno script.

La directory di lavoro è la home dell’utente, non il tuo progetto. I percorsi relativi puntano nel posto sbagliato. Fai prima cd nel progetto.

Le variabili d’ambiente non ci sono. Le chiavi API e gli URL del database esportati in .bashrc non esistono. Caricali da un file nello script.

L’output sparisce. Cron invia l’output per email a MAILTO se la posta è configurata, e sulla maggior parte dei server non lo è. Reindirizza l’output su un file di log.

Le esecuzioni possono sovrapporsi. Se un job ogni cinque minuti a volte ne impiega sette, due copie girano insieme. flock -n salta un’esecuzione finché la precedente tiene il lock.

Alcune versioni di cron ignorano anche un’ultima riga che non termina con un a capo. Un crontab che tiene conto di tutto questo ha questo aspetto:

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

Come testare un’espressione cron

Rileggila a parole. Incolla l’espressione in un parser di espressioni cron e verifica che la descrizione e le prossime esecuzioni corrispondano a ciò che intendevi.

Esegui il comando nell’ambiente di cron. Un ambiente ridotto all’osso riproduce la maggior parte dei problemi del tipo “nel mio terminale funziona” prima ancora di aspettare la pianificazione.

Pianificalo una volta ogni minuto. Usa temporaneamente * * * * *, guardalo partire, poi imposta la pianificazione reale.

Verifica che sia stato cron ad avviarlo. Su Debian e Ubuntu, grep CRON /var/log/syslog o journalctl -u cron; sui sistemi basati su Red Hat, /var/log/cron o journalctl -u crond.

Conferma che il crontab sia installato con crontab -l, come l’utente che deve eseguirlo.

Per simulare l’ambiente di cron da una shell:

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

Abbina a ogni job un heartbeat

Un’espressione corretta dice a cron solo quando avviare un job. Non dice nulla sul fatto che il job sia partito o sia arrivato in fondo. Un riavvio, un crontab sovrascritto o una variabile mancante falliscono tutti in silenzio.

Un heartbeat colma questa lacuna. Il job richiama un URL univoco quando termina con successo, e il servizio di monitoraggio ti avvisa quando la richiesta non arriva nei tempi previsti:

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

Imposta l’intervallo atteso dell’heartbeat sulla stessa pianificazione dell’espressione cron, con un margine per le esecuzioni lente: 24 ore più un po’ per un job notturno, un’ora più un po’ per uno orario. Il monitoraggio dei cron job di Uptimecheck funziona così, con un avviso quando manca un ping e una notifica di ripristino quando il job torna a farsi sentire. I suoi monitor cron accettano la pianificazione del crontab nel tuo fuso orario, ricevono ping di inizio e di fine sullo stesso monitor, ti avvisano quando un’esecuzione supera la durata massima e possono registrare il codice di uscita e l’output del job. La guida su come monitorare i cron job con gli heartbeat spiega la configurazione nel dettaglio, e quella su come evitare i task cron mancati le buone abitudini che la accompagnano.

Quando un heartbeat manca all’appello, la causa è spesso sul server: un disco pieno, la memoria esaurita o un riavvio imprevisto. Il monitoraggio dei server accanto agli heartbeat ti mostra quella causa nello stesso momento.

Checklist degli errori più comuni

Limitare l’ora ma lasciare il minuto a *.

Impostare entrambi i campi dei giorni aspettandosi AND invece di OR.

Dare per scontato che il server sia nel tuo fuso orario.

Pianificare job importanti nell’ora del cambio dell’ora legale.

Usare percorsi relativi, sintassi bash o % senza escape.

Far girare un job senza heartbeat, così nessuno si accorge quando smette di funzionare.

In sintesi

Cinque campi, quattro caratteri speciali e qualche scorciatoia coprono quasi ogni pianificazione di cui avrai bisogno. Il problema è raramente l’espressione: sono i fusi orari, la regola OR per i campi dei giorni e l’ambiente spoglio di cron. Scrivi il fuso orario accanto a ogni job, usa percorsi assoluti, registra l’output e dai un heartbeat a ogni job che conta.

Gli heartbeat di Uptimecheck sono inclusi in ogni piano, anche nel piano Free, insieme al monitoraggio di uptime, SSL, domini e DNS. Inizia la prova gratuita di 14 giorni, senza carta di credito.

Domande

Che cosa significa */5 * * * * in cron?

Ogni cinque minuti: ai minuti 0, 5, 10 e così via fino a 55 di ogni ora, tutti i giorni.

Come eseguo un cron job ogni due ore?

Usa 0 */2 * * *, che viene eseguito al minuto 0 di un'ora sì e una no. Scrivere * */2 * * * invece lo esegue ogni minuto durante un'ora sì e una no.

Quale fuso orario usa cron?

Il fuso orario del sistema su cui gira. Molti server cloud e container usano UTC, quindi controlla con timedatectl o date prima di scegliere una pianificazione. Alcune implementazioni supportano una variabile CRON_TZ.

Perché il mio cron job funziona nel terminale ma non con cron?

Cron esegue i comandi con un PATH minimo, /bin/sh come shell, la home come directory di lavoro e senza il profilo della tua shell. Usa percorsi assoluti, metti l'escape ai segni % e registra l'output per vedere l'errore.

Continua a leggere

Guides 6 min di lettura

Come monitorare i cron job con gli heartbeat

I cron job falliscono in silenzio. Un monitor heartbeat ti avvisa quando un job pianificato non si fa vivo in tempo. Come funzionano gli heartbeat, come aggiungerne uno a un crontab e quali impostazioni scegliere.

Leggi

I disservizi sono acqua passata.

Configura il tuo primo monitor in meno di un minuto, oppure esplora prima la demo live.

Prova gratuita di 14 giorni · Poi gratis con 5 monitor · Nessuna carta di credito