Con crontab si dice al sistema di eseguire un comando o uno script in automatico, ogni minuto, ogni notte alle 3, il lunedì mattina, il primo del mese. È lo strumento classico per backup, pulizie, controlli periodici e ogni attività che non vuoi ricordarti di lanciare a mano.
Cos'è
cron è il servizio (demone) che resta in funzione in background e, ogni minuto, controlla se c'è qualcosa da eseguire. crontab (cron table) è sia il file in cui ogni utente scrive i propri lavori programmati, sia il comando per modificarlo. Su Debian e Ubuntu il servizio è già installato e attivo (pacchetto cron); puoi verificarlo con systemctl status cron.
Cosa fa
Ogni utente ha una propria tabella di lavori programmati, e cron li esegue con i permessi di quell'utente, all'orario indicato. Ogni riga della tabella contiene un orario, in un formato a cinque campi, e il comando da eseguire. Se il computer è spento all'ora prevista, il lavoro non viene recuperato al riavvio (a questo servono strumenti come anacron o i timer di systemd).
Come si usa
$ crontab -e # modifica la propria tabella
$ crontab -l # mostra la propria tabella
$ crontab -r # CANCELLA la propria tabella (senza conferma!)Il formato di ogni riga è:
┌───────────── minuto (0-59)
│ ┌─────────── ora (0-23)
│ │ ┌───────── giorno del mese (1-31)
│ │ │ ┌─────── mese (1-12)
│ │ │ │ ┌───── giorno della settimana (0-7: 0 e 7 sono la domenica; 1 è il lunedì)
│ │ │ │ │
* * * * * comando da eseguireUn asterisco significa "ogni valore". Gli esempi usano percorsi e nomi d'esempio (l'utente enzo, /home/enzo/...): sostituiscili con i tuoi.
Esempio 1: la prima volta con crontab -e
$ crontab -l
no crontab for enzo
$ crontab -e
no crontab for enzo - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano <---- easiest
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
Choose 1-3 [1]: 1La prima volta crontab -e chiede quale editor usare (nano è il più semplice). Si apre un file con alcune righe di commento; in fondo si aggiungono i propri lavori, una riga ciascuno. Quando si salva e si esce, cron li legge subito: non serve riavviare nulla. Il messaggio "no crontab for enzo" significa solo che la tabella è ancora vuota. Per cambiare editor in seguito: select-editor.
Esempio 2: un primo lavoro, ogni giorno alle 3:30
30 3 * * * /home/enzo/bin/backup.sh
$ crontab -l
30 3 * * * /home/enzo/bin/backup.shLettura: minuto 30, ora 3, ogni giorno del mese, ogni mese, ogni giorno della settimana: ogni notte alle 3:30. Lo script deve essere eseguibile (chmod +x). Dopo aver salvato, crontab -l mostra la tabella corrente.
Esempio 3: gli orari più comuni
* * * * * ogni minuto
*/5 * * * * ogni 5 minuti
0 * * * * ogni ora, a minuto zero
0 */2 * * * ogni 2 ore
0 9 * * 1-5 alle 9:00, dal lunedì al venerdì
30 18 * * 5 alle 18:30 di ogni venerdì
0 0 1 * * a mezzanotte del primo giorno di ogni mese
0 8,20 * * * alle 8:00 e alle 20:00
0 0 1 1 * a mezzanotte del primo gennaio
@reboot una volta, all'avvio del sistemaSi possono usare elenchi (8,20), intervalli (1-5) e passi (*/5, "ogni 5"). Esistono anche scorciatoie come @hourly, @daily, @weekly, @monthly, @yearly e @reboot. Quest'ultima è utile per lanciare qualcosa all'accensione.
Esempio 4: salvare l'output in un registro
30 3 * * * /home/enzo/bin/backup.sh >> /home/enzo/backup.log 2>&1
$ tail -n 3 /home/enzo/backup.log
2026-10-20 03:30:01 backup riuscito
2026-10-21 03:30:02 backup riuscito
2026-10-22 03:30:01 backup riuscitoUn lavoro di cron non ha un terminale su cui scrivere, quindi tutto ciò che il comando stampa andrebbe in un messaggio di posta locale (che quasi nessuno legge) o andrebbe perso. Con >> file 2>&1 si accoda sia l'output normale sia gli errori a un file di registro. Con > /dev/null 2>&1 si scarta tutto, ma così non si vedranno nemmeno gli errori: meglio farlo solo per lavori di cui non serve niente.
Esempio 5: il problema dell'ambiente e dei percorsi
$ crontab -l
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""
0 4 * * * cd /home/enzo/progetto && /usr/bin/python3 aggiorna.py >> /home/enzo/aggiorna.log 2>&1Un lavoro di cron parte con un ambiente molto ridotto: un PATH minimo, nessuna delle variabili del tuo terminale, e la cartella di lavoro è la tua home. Per questo molti comandi che funzionano nel terminale falliscono dentro cron. Le regole pratiche: usa percorsi assoluti (/usr/bin/python3, non python3; per trovarli c'è which python3), spostati con cd nella cartella giusta, e se serve imposta PATH in cima alla tabella. MAILTO="" disattiva l'invio della posta locale; con un indirizzo reale, cron ti invia l'output per email (se il computer ha un sistema di posta configurato).
Esempio 6: il carattere % ha un significato speciale
0 2 * * * tar czf /backup/sito-$(date +\%F).tar.gz /var/www/sito
0 2 * * * tar czf /backup/sito-$(date +%F).tar.gz /var/www/sito # SBAGLIATOIn una riga della tabella il carattere % viene interpretato da cron come "a capo": il comando viene troncato al primo % e il resto gli arriva come input, quindi date +%F non funziona. Va quindi protetto con la barra inversa: \%. È l'errore più comune quando si usa date in un lavoro programmato. In alternativa si sposta tutto in uno script, dove % non dà problemi.
Esempio 7: più comandi, e uno script come buona pratica
0 3 * * * /home/enzo/bin/pulizia.sh >> /home/enzo/pulizia.log 2>&1
*/10 * * * * /home/enzo/bin/controllo-sito.sh || echo "sito non risponde" >> /home/enzo/allarmi.logQuando un lavoro richiede più di un comando, conviene scrivere uno script e chiamare solo quello: è più leggibile, più facile da provare a mano e senza i problemi di % e di virgolette. Per i controlli, come quello della raggiungibilità di un sito con curl, il codice di uscita permette di reagire con || (esegui l'altro comando solo se il primo fallisce).
Esempio 8: backup programmato con rsync via SSH
15 2 * * * /usr/bin/rsync -az --delete -e "ssh -o BatchMode=yes" /home/enzo/documenti/ web:/home/enzo/backup/documenti/ >> /home/enzo/rsync.log 2>&1Combinando rsync e ssh si ottiene un backup notturno. Funziona senza intervento solo con l'accesso a chiave e senza passphrase sulla chiave usata, oppure con una chiave dedicata e limitata a quel solo compito: cron non ha accesso all'ssh-agent della tua sessione grafica. BatchMode=yes fa fallire subito il collegamento invece di restare in attesa di una password che nessuno scriverà.
Esempio 9: evitare che lo stesso lavoro si sovrapponga
*/5 * * * * /usr/bin/flock -n /tmp/sincronizza.lock /home/enzo/bin/sincronizza.shSe un lavoro dura più dell'intervallo (per esempio una sincronizzazione ogni 5 minuti che una volta ne richiede 8), cron ne avvia comunque una nuova copia, e le due possono rovinarsi a vicenda. flock -n prende un "lucchetto" su un file: se è già preso, la nuova esecuzione rinuncia subito e senza fare danni.
Esempio 10: provare un lavoro prima di programmarlo
$ env -i SHELL=/bin/sh PATH=/usr/bin:/bin HOME="$HOME" /home/enzo/bin/backup.sh
$ echo $?
0
# riga da scrivere nell'editor di crontab -e, per verificare che cron funzioni:
* * * * * date >> /tmp/prova-cron.log
# dopo un paio di minuti, nel terminale:
$ cat /tmp/prova-cron.log
Tue 20 Oct 2026 04:36:01 CESTIl comando env -i lancia lo script con un ambiente quasi vuoto, simile a quello di cron: se funziona così, in genere funzionerà anche nella tabella. Per verificare che il servizio funzioni davvero si può programmare, per un minuto o due, un semplice date ogni minuto su un file di prova (quella riga va scritta nell'editor di crontab -e, non nel terminale); quando hai finito, toglila.
Esempio 11: dove guardare quando non parte
$ grep CRON /var/log/syslog | tail -n 3
Oct 20 04:35:01 pc CRON[8841]: (enzo) CMD (/home/enzo/bin/backup.sh >> /home/enzo/backup.log 2>&1)
$ journalctl -u cron --since "1 hour ago"
$ systemctl status cronIl registro di sistema mostra ogni lavoro avviato da cron, con utente e comando. Se la riga compare, il lavoro è partito (e il problema sta nel comando); se non compare, la riga della tabella non è valida o il servizio non è attivo. Sulle distribuzioni senza /var/log/syslog si usa journalctl -u cron (su alcune il servizio si chiama crond).
Esempio 12: i lavori di sistema e le cartelle cron.*
$ ls /etc/cron.d/ /etc/cron.daily/
/etc/cron.d/:
e2scrub_all sysstat
/etc/cron.daily/:
apt-compat dpkg logrotate man-db
$ sudo crontab -u enzo -l
$ sudo crontab -eOltre alla tabella personale esistono quelle di sistema: il file /etc/crontab e i file in /etc/cron.d/ hanno un campo in più, l'utente, tra l'orario e il comando. Gli script messi in /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly e /etc/cron.monthly vengono eseguiti con la cadenza indicata dal nome, senza dover scrivere gli orari. Con sudo crontab -e si modifica la tabella di root, quella adatta ai lavori che richiedono privilegi (il nome file in cron.daily non deve contenere punti e lo script deve essere eseguibile). Con -u utente si accede alla tabella di un altro utente.
Esempio 13: salvare una copia della tabella
$ crontab -l > ~/crontab-backup.txt
$ crontab ~/crontab-backup.txtCon crontab -l > file si salva la tabella in un file; con crontab file la si ripristina, sostituendo tutta la tabella attuale. Conviene farlo prima di modifiche importanti, e soprattutto per il motivo spiegato nel prossimo paragrafo: crontab -r cancella tutto senza chiedere conferma.
Opzioni utili
-e: modifica la tabella (la controlla anche, prima di salvarla, in caso di errori di sintassi).-l: mostra la tabella.-r: cancella la tabella;-i(con-r) chiede prima conferma:crontab -ri.-u utente: lavora sulla tabella di un altro utente (servesudo).crontab file: sostituisce la tabella con il contenuto del file.- Variabili in cima alla tabella:
SHELL,PATH,MAILTO(eCRON_TZnelle versioni che la supportano, per un fuso orario diverso). - Scorciatoie:
@reboot,@hourly,@daily,@weekly,@monthly,@yearly.
Attenzione a
crontab -rcancella tutto, senza conferma, e larè accanto allaesulla tastiera. Un errore di battitura costa tutta la tabella. Tieni una copia concrontab -l > file, o usa l'abitudine dicrontab -ri.crontabsenza opzioni né file legge la nuova tabella dallo standard input e, a Ctrl+D, sostituisce quella esistente: se volevi solo guardarla, il comando giusto ècrontab -l. Con Ctrl+C la tabella resta com'era.- L'ambiente è diverso dal tuo terminale:
PATHridotto, nessuna variabile, nessun terminale. Usa percorsi assoluti per programmi e file e, se serve, imposta le variabili in cima alla tabella o nello script. %va protetto con\%(o spostato in uno script).- La shell è
/bin/sh(su Debian e Ubuntu,dash): costrutti specifici dibash, come[[ ]]o<(...), nella riga non funzionano. AggiungiSHELL=/bin/bashin cima, oppure scrivi uno script con#!/bin/bash. - Giorno del mese e giorno della settimana insieme: se indichi entrambi (
0 9 15 * 1) il lavoro parte quando uno qualsiasi dei due corrisponde, non entrambi. Per "il primo lunedì del mese" serve un controllo dentro lo script. - Gli orari sono quelli del server: controlla con
dateetimedatectlin che fuso orario è il computer. Con l'ora legale, i lavori programmati nell'ora che salta o si ripete (di solito tra le 2 e le 3 del mattino) possono non partire o partire due volte: evita quelle ore per i lavori critici. - Se il computer è spento, il lavoro salta:
cronnon recupera. Per i computer non sempre accesi,anacrono i timer disystemdconPersistent=truesono la scelta giusta. - Output non gestito: senza redirezione, l'output va in un messaggio di posta locale (se c'è un sistema di posta) o si perde. Guarda sempre almeno gli errori, con
>> file 2>&1. - Troppi lavori ravvicinati e sovrapposizioni: un lavoro che dura più dell'intervallo si sovrappone a sé stesso; usa
flocke non programmare troppi lavori pesanti allo stesso minuto (per esempio, tutti a mezzanotte). - Permessi giusti: il lavoro gira con i permessi dell'utente proprietario della tabella. Per operazioni che richiedono privilegi usa la tabella di
root(sudo crontab -e), nonsudodentro la riga (chiederebbe una password che nessuno può scrivere). - Mettere password nella riga: la tabella (e la riga di comando, visibile con
ps) non è il posto per password o token. Usa file con permessi600o l'accesso a chiave. - L'ultima riga va chiusa con un a capo: se ripristini la tabella da un file scritto a mano, assicurati che l'ultima riga termini con un a capo, altrimenti può essere ignorata.
- Esiste un'alternativa moderna: i timer di
systemd(systemctl list-timers) offrono recupero dei lavori saltati, registri integrati (journalctl) e controllo delle dipendenze, a costo di una configurazione più lunga.cronresta la scelta più semplice e universale.
Riepilogo
| Comando / riga | Cosa fa |
|---|---|
crontab -e | Modifica la propria tabella |
crontab -l | Mostra la propria tabella |
crontab -r / crontab -ri | Cancella la tabella (senza conferma / con conferma) |
crontab -l > file | Salva una copia della tabella |
sudo crontab -u utente -l | Mostra la tabella di un altro utente |
30 3 * * * comando | Ogni giorno alle 3:30 |
*/5 * * * * comando | Ogni 5 minuti |
0 9 * * 1-5 comando | Alle 9:00, dal lunedì al venerdì |
0 0 1 * * comando | Il primo di ogni mese, a mezzanotte |
@reboot comando | All'avvio del sistema |
... >> log 2>&1 | Salva output ed errori in un registro |
\% | Carattere % dentro la tabella |
flock -n lock comando | Evita che il lavoro si sovrapponga a sé stesso |
grep CRON /var/log/syslog | Controlla quali lavori sono partiti |