Guida

Crontab: esempi di pianificazione delle attività in Linux, sintassi ed errori comuni

Aggiornato: · Skillaria.Top

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:

ComandoCosa fa
crontab -eapre la propria tabella nell'editor (al primo avvio chiede di scegliere un editor)
crontab -lmostra la tabella attuale
crontab -relimina l'intera tabella, senza conferma
crontab -i -relimina con conferma (Debian/Ubuntu, RHEL)
sudo crontab -u alice -emodifica la tabella di un altro utente
crontab filesostituisce 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:

CarattereSignificatoEsempio
*qualsiasi valore* * * * * — ogni minuto
,elenco0 9,18 * * * — alle 9:00 e alle 18:00
-intervallo0 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

PianificazioneRiga del crontab
ogni minuto* * * * *
ogni 5 minuti*/5 * * * *
ogni 30 minuti*/30 * * * * oppure 0,30 * * * *
ogni ora, all'inizio dell'ora0 * * * *
ogni 6 ore0 */6 * * *
ogni giorno alle 3:000 3 * * *
ogni giorno alle 23:4545 23 * * *
nei giorni feriali alle 9:000 9 * * 1-5
nel fine settimana a mezzogiorno0 12 * * 6,0
il lunedì alle 8:3030 8 * * 1
il primo giorno di ogni mese alle 00:000 0 1 * *
una volta al trimestre0 0 1 1,4,7,10 *
una volta all'anno, il 1° gennaio0 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:

AliasEquivalente
@rebootuna sola volta all'avvio del demone cron (dopo il boot del sistema)
@hourly0 * * * *
@daily / @midnight0 0 * * *
@weekly0 0 * * 0
@monthly0 0 1 * *
@yearly / @annually0 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 avvia run-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.

Impara l’argomento in video

Questo argomento è trattato in modo approfondito, con pratica, nel corso «Linux: с нуля до уверенного администрирования».

Vai al corso