Crontab: esempi di pianificazione delle attività in Linux, sintassi ed errori comuni
Crontab è la tabella di pianificazione con cui il demone cron avvia i comandi: ogni riga contiene cinque campi temporali (minuto, ora, giorno del mese, mese, giorno della settimana) e il comando, per esempio */5 * * * * /opt/backup.sh esegue lo script ogni 5 minuti. La tabella si modifica con crontab -e, e la maggior parte dei problemi nasce dall'ambiente ridotto di cron: usa percorsi completi e reindirizza l'output in un log.
Cron è il pianificatore standard di Linux: il demone cron legge ogni minuto le tabelle di pianificazione (crontab) ed esegue i comandi il cui momento è arrivato. Così si fanno i backup notturni, si ripuliscono i file temporanei, si rinnovano i certificati e si inviano report. Qui sotto trovi la sintassi, esempi di crontab per i casi più comuni e l'analisi degli errori per cui un'attività non viene eseguita «in silenzio».
Come aprire e modificare il crontab
Ogni utente ha la propria tabella. Si lavora con il comando crontab, non modificando direttamente i file in /var/spool/cron:
| Comando | Cosa fa |
|---|---|
crontab -e | apre la propria tabella nell'editor (al primo avvio chiede di scegliere un editor) |
crontab -l | mostra la tabella attuale |
crontab -r | elimina l'intera tabella, senza conferma |
crontab -i -r | elimina con conferma (Debian/Ubuntu, RHEL) |
sudo crontab -u alice -e | modifica la tabella di un altro utente |
crontab file | sostituisce la tabella con il contenuto di un file |
Dopo il salvataggio crontab -e verifica la sintassi e scrive crontab: installing new crontab. Se una riga è errata, compare errors in crontab file, can't install e ti viene proposto di modificare di nuovo. Non serve riavviare il demone: le modifiche vengono recepite automaticamente.
Attenzione con -r: le lettere e e r sono vicine sulla tastiera, e non esiste una copia di sicurezza della tabella. Buona abitudine è tenere un backup:
crontab -l > ~/crontab.bak
# ripristino
crontab ~/crontab.bak
Sintassi del crontab: cinque campi temporali
Ogni riga di attività ha questa forma:
# ┌───────── minuto (0–59)
# │ ┌─────── ora (0–23)
# │ │ ┌───── giorno del mese (1–31)
# │ │ │ ┌─── mese (1–12 oppure jan–dec)
# │ │ │ │ ┌─ giorno della settimana (0–7 oppure sun–sat; 0 e 7 sono domenica)
# │ │ │ │ │
* * * * * comando
In ogni campo si possono usare caratteri speciali:
| Carattere | Significato | Esempio |
|---|---|---|
* | qualsiasi valore | * * * * * — ogni minuto |
, | elenco | 0 9,18 * * * — alle 9:00 e alle 18:00 |
- | intervallo | 0 9-18 * * * — ogni ora dalle 9 alle 18 |
/ | passo | */15 * * * * — ogni 15 minuti |
Il passo si può combinare con un intervallo: 0 8-20/2 * * * — ogni due ore dalle 8 alle 20 (8, 10, …, 20). L'orario segue il fuso orario del sistema: verificalo con timedatectl.
Esempi di crontab per ogni giorno
| Pianificazione | Riga del crontab |
|---|---|
| ogni minuto | * * * * * |
| ogni 5 minuti | */5 * * * * |
| ogni 30 minuti | */30 * * * * oppure 0,30 * * * * |
| ogni ora, all'inizio dell'ora | 0 * * * * |
| ogni 6 ore | 0 */6 * * * |
| ogni giorno alle 3:00 | 0 3 * * * |
| ogni giorno alle 23:45 | 45 23 * * * |
| nei giorni feriali alle 9:00 | 0 9 * * 1-5 |
| nel fine settimana a mezzogiorno | 0 12 * * 6,0 |
| il lunedì alle 8:30 | 30 8 * * 1 |
| il primo giorno di ogni mese alle 00:00 | 0 0 1 * * |
| una volta al trimestre | 0 0 1 1,4,7,10 * |
| una volta all'anno, il 1° gennaio | 0 0 1 1 * |
| ogni 10 minuti in orario di lavoro | */10 9-18 * * 1-5 |
Una riga completa di attività è la pianificazione seguita dal comando:
# backup del database ogni notte alle 3:00
0 3 * * * /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1
# pulizia dei file temporanei più vecchi di 7 giorni, la domenica
0 4 * * 0 /usr/bin/find /tmp/app -type f -mtime +7 -delete
# controllo del sito ogni 5 minuti
*/5 * * * * /usr/bin/curl -fsS https://example.com/health > /dev/null || /usr/local/bin/alert.sh
Alias speciali @reboot, @daily e altri
Al posto dei cinque campi si può scrivere un breve alias:
| Alias | Equivalente |
|---|---|
@reboot | una sola volta all'avvio del demone cron (dopo il boot del sistema) |
@hourly | 0 * * * * |
@daily / @midnight | 0 0 * * * |
@weekly | 0 0 * * 0 |
@monthly | 0 0 1 * * |
@yearly / @annually | 0 0 1 1 * |
@reboot /home/alice/bin/start-tunnel.sh >> /home/alice/tunnel.log 2>&1
Per i servizi che devono restare sempre attivi e ripartire in caso di crash, @reboot è una soluzione debole: meglio un'unità systemd con Restart=on-failure.
Come eseguire un'attività ogni N secondi
L'unità minima di cron è un minuto. Se servono esecuzioni più frequenti, ci sono due approcci. Il primo sono più righe sfalsate con sleep:
* * * * * /opt/check.sh
* * * * * sleep 30; /opt/check.sh
Il secondo, più corretto, è un timer systemd con OnUnitActiveSec=30s. Se un'attività deve girare più di una volta al minuto, di solito è compito di un demone o di un timer, non di cron.
Crontab di sistema: /etc/crontab e /etc/cron.d
Oltre alle tabelle degli utenti esistono quelle di sistema. Il formato è diverso: tra l'orario e il comando c'è il nome utente con cui eseguire il comando.
# /etc/cron.d/certbot-renew
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root certbot renew --quiet
Dove stanno le cose:
/etc/crontab— la tabella di sistema principale; in Debian/Ubuntu da essa partono le cartelle sottostanti./etc/cron.d/— file separati con attività, comodi da installare con i pacchetti o tramite Ansible./etc/cron.hourly/,cron.daily/,cron.weekly/,cron.monthly/— qui si mettono gli script eseguibili senza orario; li avviarun-parts(o anacron).
Trappola di run-parts: in Debian e Ubuntu salta i file il cui nome contiene un punto. Lo script backup.sh in /etc/cron.daily/ non parte: chiamalo backup. Per vedere cosa verrebbe eseguito usa run-parts --test /etc/cron.daily.
I file in /etc/cron.d/ devono appartenere a root, non essere scrivibili dal gruppo né dagli altri e terminare con un a capo — altrimenti cron li ignora.
Ambiente di cron: PATH, SHELL e variabili
La causa principale della frase «nel terminale funziona, in cron no» è l'ambiente. Cron avvia i comandi tramite /bin/sh, senza leggere il tuo .bashrc né il .profile, con un PATH minimo (di solito /usr/bin:/bin). Perciò docker, node o php installati in /usr/local/bin potrebbero non essere trovati.
Le variabili si possono definire all'inizio della tabella:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
CRON_TZ=Europe/Rome
0 6 * * * cd /srv/app && ./report.sh
MAILTO— a chi inviare l'output dell'attività;MAILTO=""disattiva le email.CRON_TZ— fuso orario per la pianificazione (supportato da cronie su RHEL/Fedora; nella versione di cron di Debian questa variabile non funziona).- Nei valori delle variabili non ci sono sostituzioni come
$HOME/bin— scrivi i percorsi per esteso.
La soluzione più affidabile è indicare nell'attività percorsi assoluti verso tutti i programmi e i file, e mettere nella prima riga degli script lo shebang: #!/bin/bash.
Dove leggere i log di cron
Cron registra nel journal il fatto che un'attività è partita, ma non il suo output:
# Debian/Ubuntu
grep CRON /var/log/syslog
# tramite systemd-journald
journalctl -u cron --since today # Debian/Ubuntu
journalctl -u crond --since today # RHEL, Fedora, Rocky
# RHEL senza journald
tail -f /var/log/cron
La riga di avvio ha questo aspetto:
Oct 14 03:00:01 web1 CRON[21544]: (root) CMD (/usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1)
Per vedere cosa ha stampato l'attività e con quale errore si è fermata, reindirizza sia stdout sia stderr in un file: >> /var/log/job.log 2>&1. Senza questo, l'output viene inviato per posta locale, e se non è installato alcun agente di posta si perde (nel journal compare No MTA installed, discarding output).
Perché cron non esegue l'attività: errori comuni
Comando non trovato
Sintomo: nel log dell'attività compare command not found. Causa: PATH ridotto. Soluzione: percorso completo del programma (which docker te lo indica) oppure una riga PATH= in cima alla tabella.
Segno di percentuale nel comando
Nel crontab il carattere % significa a capo: tutto ciò che segue il primo % viene passato al comando come input standard. Per questo la classica riga con la data nel nome del file si rompe:
# sbagliato — il comando viene troncato al primo %
0 2 * * * tar czf /backup/site-$(date +%F).tar.gz /var/www
# corretto — con escape
0 2 * * * tar czf /backup/site-$(date +\%F).tar.gz /var/www
Ancora più semplice: sposta la logica in uno script, dove il % non va escapato.
Script non eseguibile o con fine riga sbagliati
L'errore Permission denied indica che il file non ha il bit x: esegui chmod +x script.sh oppure avvialo esplicitamente con /bin/bash /opt/script.sh. Se lo script è stato scritto su Windows, i fine riga CRLF producono un errore strano /bin/bash^M: bad interpreter — si corregge con sed -i 's/\r$//' script.sh oppure con dos2unix.
Percorsi relativi e directory di lavoro
L'attività parte nella home dell'utente. Se lo script legge ./config.ini, lo cercherà in ~. Premetti cd /srv/app && al comando oppure usa percorsi assoluti dentro lo script.
Giorno del mese e giorno della settimana insieme
Se sono impostati entrambi, cron parte quando coincide almeno uno dei due, non entrambi. La riga 0 9 13 * 5 parte il 13 del mese e ogni venerdì, non solo il venerdì 13. La condizione giusta va verificata dentro il comando:
0 9 13 * * [ "$(date +\%u)" = 5 ] && /opt/friday13.sh
Attività che si sovrappongono
Se un backup dura più dell'intervallo, la successiva esecuzione parte sopra la precedente. Protezione: un blocco con flock:
*/10 * * * * /usr/bin/flock -n /tmp/sync.lock /opt/sync.sh
Con il flag -n la seconda istanza termina subito se la prima è ancora in corso.
Il demone cron non è in esecuzione
Controlla con systemctl status cron (su RHEL crond). Nelle immagini minimali, per esempio nei container Docker, il demone cron non c'è affatto: le attività nel crontab non hanno chi le esegua.
Come fare il debug di un'attività cron
Lancia il comando in un ambiente il più possibile simile a quello di cron:
env -i SHELL=/bin/sh PATH=/usr/bin:/bin HOME=$HOME /bin/sh -c '/opt/backup.sh'
Se qui si verifica un errore, lo stesso errore comparirà in cron. Imposta temporaneamente la pianificazione * * * * *, reindirizza l'output in un file e seguilo con tail -f. Per controllare la pianificazione stessa sono utili i calcolatori online di espressioni cron, ma l'ultima parola spetta al log di sistema.
Chi può usare cron: cron.allow e cron.deny
L'accesso è regolato dai file /etc/cron.allow e /etc/cron.deny. Se esiste cron.allow, il crontab è disponibile solo agli utenti elencati al suo interno. Se non c'è, ma esiste cron.deny, è disponibile a tutti tranne a quelli elencati. Un utente vietato che esegue crontab -e riceve il messaggio You (bob) are not allowed to use this program.
Conclusioni
Un crontab è composto da righe con cinque campi temporali e un comando: */5 * * * * ogni 5 minuti, 0 3 * * * ogni notte, 0 9 * * 1-5 nei giorni feriali. Modifica la tabella con crontab -e, usa percorsi assoluti, escapa il %, scrivi l'output in un log e proteggi le attività lunghe con flock. Gli esempi di crontab mostrati coprono la maggior parte dei compiti sui server, e l'automazione e la pianificazione sono trattate in pratica nel corso di Linux.
Domande frequenti
In cosa cron si differenzia da anacron?
Cron esegue le attività all'ora precisa e le salta se il computer era spento in quel momento. Anacron garantisce che le attività giornaliere, settimanali e mensili vengano eseguite dopo l'accensione, per questo è adatto a portatili e desktop.
È meglio cron o i timer systemd?
Cron è più semplice e si trova quasi ovunque. I timer systemd danno i log in journalctl, le dipendenze, la limitazione delle risorse e l'opzione Persistent=true per le esecuzioni perse, quindi sui server moderni vengono scelti sempre più spesso per le attività importanti.
Dove è fisicamente memorizzato il crontab di un utente?
Su Debian e Ubuntu in /var/spool/cron/crontabs/nome, su RHEL e Fedora in /var/spool/cron/nome. Non conviene modificare direttamente questi file: usa crontab -e.
Come disattivare temporaneamente un'attività nel crontab?
Commenta la riga con il simbolo # all'inizio tramite crontab -e. Per disattivare tutte le attività di un utente, salva la tabella in un file con crontab -l e poi eliminala con crontab -r.
Come eseguire un'attività nell'ultimo giorno del mese?
Non esiste un campo dedicato. Pianifica l'attività per i giorni dal 28 al 31 e verifica nel comando che il giorno dopo sia il primo: 0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /opt/job.sh.
Questo argomento è trattato in modo approfondito, con pratica, nel corso «Linux: с нуля до уверенного администрирования».
Vai al corso