Come scrivere un'espressione cron: cinque campi e la regola OR di cui nessuno parla
Pubblicato il 21/05/2026 · 9 min di lettura · Strumenti per sviluppatori
Daniel Okonkwo — Sviluppatore front-end e redattore Tech presso Allin
Performance web · Formati di file
Verificato su 2 fonti
Un'espressione cron è fatta di cinque campi separati da spazi, letti da sinistra a destra: minuto (0-59), ora (0-23), giorno del mese (1-31), mese (1-12 o nomi di tre lettere) e giorno della settimana (0-6 in POSIX con 0 come domenica, esteso a 0-7 da quasi tutte le implementazioni così che anche 7 sia domenica). Un asterisco indica tutti i valori dell'intervallo di quel campo. Un trattino forma un intervallo inclusivo: 8-11 nel campo dell'ora è 8, 9, 10 e 11. Una virgola forma un elenco, ed elenchi e intervalli si mescolano: 1-3,7-9. Una barra aggiunge un passo, ed è qui che si sbaglia la prima volta — un passo percorre un intervallo, non fissa una cadenza: */15 nel campo dei minuti è 0, 15, 30 e 45, e */40 è 0 e 40 e poi nulla finché l'ora successiva non riparte con l'intervallo. La seconda trappola, più grave, è che giorno del mese e giorno della settimana si combinano con OR e non con AND. Se entrambi sono ristretti, il lavoro parte quando uno qualsiasi dei due corrisponde. Quindi 0 0 1 * 1 non significa il primo lunedì del mese: scatta a mezzanotte del giorno 1 di ogni mese E a mezzanotte di ogni lunedì. Per fissare un lavoro a un preciso giorno della settimana, lascia il giorno del mese come asterisco, e viceversa. Tutto il resto che incontrerai — @daily, un sesto campo dei secondi, il carattere ?, L, W e # — è fuori dallo standard e dipende interamente dal cron che stai eseguendo.
Minuto, ora, giorno del mese, mese, giorno della settimana. Le trappole: un passo è un'andatura dentro un intervallo e non una cadenza, e i due campi del giorno si combinano con OR — quindi 0 0 1 * 1 scatta il giorno 1 e ogni lunedì.
Cinque campi, e un passo non è una cadenza
Leggi i campi da sinistra a destra e la notazione sta in testa. L'asterisco rappresenta l'intero intervallo del suo campo. Il trattino forma un intervallo inclusivo: 8-11 nel campo dell'ora sono quattro ore, non tre. La virgola forma un elenco, ed elenchi e intervalli si combinano liberamente nello stesso campo: 1-3,7-9 è un insieme legale di sei valori. I nomi possono sostituire i numeri nei campi mese e giorno della settimana, con tre lettere, benché il cron Vixie classico non accetti intervalli né elenchi costruiti con nomi — 1-3 viene interpretato dove JAN-MAR può fallire, buona ragione per restare ai numeri in tutto ciò che deve essere portabile.
La barra è il punto in cui il modello mentale si rompe. Un passo percorre un intervallo, non è una cadenza di ripetizione, e l'intervallo riparte all'inizio di ogni unità superiore. Nel campo dei minuti, */15 percorre 0, 15, 30, 45, poi l'ora cambia e riparte da 0 — il che risulta essere esattamente ogni quindici minuti, quindi nessuno nota la differenza. Scrivi */40 e l'illusione crolla: percorre 0 e 40, poi l'ora cambia e riparte da 0, dando intervalli di quaranta minuti e poi di venti. Lo stesso vale per un intervallo limitato: 0-23/2 nel campo dell'ora sono le ore pari, e 1-9/2 sono 1, 3, 5, 7 e 9. Se ti serve davvero una cadenza che non divide la sua unità, cron non può esprimerla in una riga: servono due voci o una guardia dentro il comando.
I due campi del giorno si combinano con OR, non con AND
Questa è la regola che quasi tutte le spiegazioni sbagliano, e non è una stranezza di una singola implementazione: è scritta nella specifica. POSIX stabilisce che, se il giorno del mese è dato come elemento o elenco e anche il giorno della settimana lo è, allora vale qualunque giorno che corrisponda al giorno del mese oppure al giorno della settimana. Il manuale crontab(5) dice lo stesso in parole più semplici e dà l'esempio canonico: 30 4 1,15 * 5 parte alle 4:30 del mattino il giorno 1 e il 15 di ogni mese, più ogni venerdì. Non il 1 o il 15 quando cadono di venerdì. Entrambi gli insiemi, uniti.
Le regole pratiche che ne derivano sono brevi. Se esattamente uno dei due campi del giorno è un asterisco, comanda l'altro e non c'è ambiguità — è il caso da scrivere quasi sempre. Se entrambi sono asterischi, ogni giorno corrisponde, ed è altrettanto univoco. Solo quando entrambi sono ristretti entra in gioco l'unione, e il risultato non è quasi mai quello voluto: 0 0 1 * 1 scatta circa cinque volte al mese invece di una. Non esiste una sintassi cron per l'intersezione, quindi se ti serve davvero il primo lunedì del mese il trucco standard è pianificare l'unione e restringerla dentro il comando — farlo partire su 0 0 1-7 * 1 e aprire lo script con un test che il giorno della settimana sia lunedì, oppure su 0 0 * * 1 con un test che il giorno del mese sia 7 o meno. I cron in stile Quartz aggiungono un operatore # per questo, ma nel cron di sistema non c'è.
Tutto ciò che va oltre i cinque campi dipende dall'implementazione
POSIX definisce cinque campi, l'asterisco, gli intervalli, gli elenchi e nient'altro. Ogni comodità che hai visto oltre a questo è un'estensione, e le estensioni variano. Il passo con la barra è un'estensione Vixie oggi quasi universale ma tuttora fuori dallo standard. Le stringhe abbreviate — @yearly e il suo sinonimo @annually, @monthly, @weekly, @daily e il suo sinonimo @midnight, @hourly, e @reboot — vengono dalla stessa stirpe, e @reboot in particolare non ha significato fisso fra i sistemi, perché che cosa conti come riavvio dipende dal servizio. Un sesto campo per i secondi è comune negli scheduler applicativi come Quartz, Spring e diverse librerie Node, e assente dal cron di sistema: un'espressione copiata dalla documentazione di un framework dentro una crontab risulterà spostata di un campo e pianificherà tutt'altro anziché fallire rumorosamente.
Il punto interrogativo appartiene alla stessa famiglia. In Quartz significa nessun valore specifico ed esiste proprio per risolvere l'ambiguità fra giorno del mese e giorno della settimana dichiarando irrilevante un campo; il cron di sistema non lo accetta affatto. Gli operatori L, W e # per ultimo giorno del mese, giorno feriale più vicino ed ennesimo giorno della settimana sono anch'essi solo di Quartz. Due fatti d'ambiente pesano più di tutta questa sintassi: il servizio esegue i lavori nel fuso orario per cui è configurato, quindi un'espressione corretta in un'installazione può scattare un'ora prima o dopo in un'altra, e attorno a un cambio dell'ora un lavoro pianificato nell'ora saltata può non partire affatto mentre uno nell'ora ripetuta può partire due volte. E cron è un innesco, non un esecutore di lavori — nessun tentativo ripetuto, nessun controllo di concorrenza, nessuna memoria che l'esecuzione precedente sia fallita. Se due invocazioni non devono sovrapporsi, prendi tu stesso un lock dentro il comando.
| Posizione | Campo | Valori ammessi | L'errore che invita |
|---|---|---|---|
| 1º | Minuto | 0-59 | Scrivere * qui quando si intendeva 0 — un'espressione come * 3 * * * parte sessanta volte, ogni minuto dell'ora delle 3 del mattino |
| 2º | Ora | 0-23 | Ragionare con l'orologio a 12 ore: non esistono il 24 né il pm, mezzanotte è 0 e le 23 sono 23 |
| 3º | Giorno del mese | 1-31 | Usare 31 aspettandosi dodici esecuzioni all'anno: i mesi più corti semplicemente non corrispondono mai, quindi il lavoro salta in silenzio febbraio, aprile, giugno, settembre e novembre |
| 4º | Mese | 1-12, oppure JAN fino a DEC | Dare per scontato che i nomi funzionino ovunque: il cron Vixie classico accetta i nomi di tre lettere ma rifiuta intervalli o elenchi di essi, quindi JAN-MAR può non essere interpretato dove 1-3 lo è |
| 5º | Giorno della settimana | 0-6 in POSIX con 0 come domenica; 0-7 in quasi tutte le implementazioni, dove anche 7 è domenica | Restringere questo campo e il giorno del mese insieme: i due sono in OR, quindi il lavoro scatta su entrambi gli insiemi di giorni e non sulla loro intersezione |
Domande frequenti
- Che cosa significa esattamente */15?
- Nel campo dei minuti seleziona i valori 0, 15, 30 e 45 — un passo di quindici lungo l'intervallo da 0 a 59, partendo dal primo valore dell'intervallo. Non è un timer che scatta quindici minuti dopo l'ultima esecuzione, e non sopravvive a una divisione non esatta: */40 nel campo dei minuti seleziona solo 0 e 40, quindi gli scarti sono di quaranta minuti e poi di venti quando l'ora successiva riparte con l'intervallo. Se vuoi una cadenza misurata dall'ultima esecuzione e non dall'inizio dell'ora, cron è lo strumento sbagliato: un timer systemd con OnUnitActiveSec, o un ciclo dentro un processo di lunga durata, è quello giusto.
- Come eseguo un lavoro ogni 90 minuti?
- Non in una sola riga, perché 90 non divide 60 e un passo resta confinato a un unico campo. Lo schema però si ripete ogni tre ore, quindi due voci lo coprono esattamente: 0 */3 * * * dà le 00:00, 03:00, 06:00 e così via, e 30 1-23/3 * * * dà le 01:30, 04:30, 07:30 e così via. Insieme producono un'esecuzione ogni novanta minuti, e la sequenza si chiude in modo pulito a mezzanotte perché ventiquattro ore sono esattamente sedici intervalli da novanta minuti. Lo stesso trucco a due voci vale per qualsiasi cadenza che divida un numero intero di ore; ciò che non lo fa, come ogni 50 minuti, non è esprimibile in cron affatto.
- Perché il mio lavoro notturno è partito due volte, o per niente?
- La causa abituale è un cambio dell'ora. Cron confronta l'orologio da parete: quando l'orologio avanza, un'ora che non è mai esistita non viene mai soddisfatta e un lavoro pianificato lì dentro semplicemente non parte; quando l'orologio arretra, un'ora si verifica due volte e un lavoro pianificato lì dentro può scattare due volte. Le implementazioni differiscono nello sforzo di compensare, ed è per questo che la stessa crontab si comporta diversamente su due distribuzioni. Le correzioni affidabili sono pianificare i lavori delicati fuori dalla finestra di transizione, far girare il servizio in un fuso senza cambi d'ora, oppure rendere il comando stesso sicuro da eseguire due volte. Quest'ultima conviene comunque: l'idempotenza ti protegge anche da tentativi ripetuti, esecuzioni sovrapposte e rilanci manuali.
Articoli che potrebbero interessarti
Tutte le guide →Strumenti correlati
Fonti
Hai notato un errore in questo articolo?