Salta al contenuto principale

crontab: eseguire comandi in automatico a orari stabiliti

Inviato da tuxsa il

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 eseguire

Un 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]: 1

La 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.sh

Lettura: 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 sistema

Si 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 riuscito

Un 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>&1

Un 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   # SBAGLIATO

In 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.log

Quando 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>&1

Combinando 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.sh

Se 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 CEST

Il 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 cron

Il 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 -e

Oltre 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.txt

Con 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 (serve sudo).
  • crontab file: sostituisce la tabella con il contenuto del file.
  • Variabili in cima alla tabella: SHELL, PATH, MAILTO (e CRON_TZ nelle versioni che la supportano, per un fuso orario diverso).
  • Scorciatoie: @reboot, @hourly, @daily, @weekly, @monthly, @yearly.

Attenzione a

  • crontab -r cancella tutto, senza conferma, e la r è accanto alla e sulla tastiera. Un errore di battitura costa tutta la tabella. Tieni una copia con crontab -l > file, o usa l'abitudine di crontab -ri.
  • crontab senza 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: PATH ridotto, 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 di bash, come [[ ]] o <(...), nella riga non funzionano. Aggiungi SHELL=/bin/bash in 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 date e timedatectl in 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: cron non recupera. Per i computer non sempre accesi, anacron o i timer di systemd con Persistent=true sono 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 flock e 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), non sudo dentro 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 permessi 600 o 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. cron resta la scelta più semplice e universale.

Riepilogo

Comando / rigaCosa fa
crontab -eModifica la propria tabella
crontab -lMostra la propria tabella
crontab -r / crontab -riCancella la tabella (senza conferma / con conferma)
crontab -l > fileSalva una copia della tabella
sudo crontab -u utente -lMostra la tabella di un altro utente
30 3 * * * comandoOgni giorno alle 3:30
*/5 * * * * comandoOgni 5 minuti
0 9 * * 1-5 comandoAlle 9:00, dal lunedì al venerdì
0 0 1 * * comandoIl primo di ogni mese, a mezzanotte
@reboot comandoAll'avvio del sistema
... >> log 2>&1Salva output ed errori in un registro
\%Carattere % dentro la tabella
flock -n lock comandoEvita che il lavoro si sovrapponga a sé stesso
grep CRON /var/log/syslogControlla quali lavori sono partiti