Oggi parliamo di una cosa fondamentale per la gestione dei sistemi: i task pianificati con cron. Alla fine di questo articolo saprai creare, modificare, cancellare e aggiornare le operazioni pianificate sul tuo Linux, sia a livello di intero sistema sia per i singoli utenti. In fondo trovi anche un piccolo esercizio.
Come funziona cron
Quando si parla di cron ci si riferisce al demone cron: un processo di sistema lanciato all’avvio, che gira sempre mentre noi lavoriamo ed è lì apposta per fare i compiti al posto nostro quando è il momento. Il demone si sveglia ogni minuto, quindi la granularità è il minuto: con le impostazioni base non puoi eseguire un task più di una volta al minuto.
Ogni minuto fa due cose:
- controlla i file cron di sistema e i crontab degli utenti, per vedere se ci sono modifiche e aggiornare la sua tabella interna dei compiti;
- controlla se in quel minuto, di quel giorno, di quel mese e così via c’è un compito da eseguire, e se sì lo esegue.
Rispetto al comando at (che esegue un’operazione una volta sola nel futuro) cron è pensato per eseguire operazioni in modo ripetuto e ciclico, a intervalli regolari, per tutta la vita del sistema.
Il file /etc/crontab
Il file più importante è /etc/crontab. Contiene le pianificazioni di sistema ed è anche responsabile di eseguire tutti gli script contenuti nelle sottocartelle /etc/cron.*. Diamogli un’occhiata:
cat /etc/crontab
Su Debian è fatto più o meno così (nel file ogni riga sta su una riga sola):
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron ||
{ cd / && run-parts --report /etc/cron.daily; }
47 6 * * 7 root test -x /usr/sbin/anacron ||
{ cd / && run-parts --report /etc/cron.weekly; }
52 6 1 * * root test -x /usr/sbin/anacron ||
{ cd / && run-parts --report /etc/cron.monthly; }
Ci sono due tipi di righe: quelle che valorizzano variabili d’ambiente (usate poi dai comandi delle righe successive) e quelle che definiscono le pianificazioni. Una riga di commento fa da leggenda: ecco i campi, nell’ordine.
- minuti: da 0 a 59
- ore: da 0 a 23
- giorno del mese: da 1 a 31
- mese: da 1 a 12
- giorno della settimana: da 0 a 7 (0 e 7 sono la domenica)
- utente che esegue il comando (solo nei file di sistema)
- comando: un qualunque comando di shell
I primi cinque campi sono una specie di parte condizionale: dicono quando la riga va eseguita. Un asterisco significa “qualunque valore”. Allenandoci sulle righe sopra:
- la prima gira al minuto 17 di ogni ora, ogni giorno;
- la seconda gira alle 6:25 di ogni giorno;
- la terza gira alle 6:47, ma solo la domenica;
- la quarta gira alle 6:52 del primo giorno di ogni mese.
Il comando run-parts prende una cartella e ne esegue tutti gli script. Quindi esistono delle cartelle in /etc che cominciano con cron. e contengono gli script da lanciare in momenti precisi:
- /etc/cron.hourly: ogni ora;
- /etc/cron.daily: ogni giorno;
- /etc/cron.weekly: ogni settimana;
- /etc/cron.monthly: ogni mese.
Il test test -x /usr/sbin/anacron controlla se esiste ed è eseguibile anacron, un’alternativa a cron: se c’è, le cartelle daily, weekly e monthly le gestisce lui e la riga di cron le ignora (il doppio || vuol dire “altrimenti”). Se anacron non è installato, ci pensa run-parts. Quindi se vuoi uno script che giri ogni ora, lo metti in /etc/cron.hourly e cron lo lancia per te.
La cartella /etc/cron.d
Le cartelle cron.* sono comode ma limitative. Se vuoi uno script ogni due ore, o a un orario diverso da quelli standard, serve un’altra strada: la cartella /etc/cron.d, dove puoi aggiungere crontab di sistema aggiuntivi. Hanno la stessa sintassi di /etc/crontab, con la colonna dell’utente.
Esempio: sono le 15:08 e voglio uno script che giri alle 15:11 di ogni giorno. Creo un file di test, come root:
sudo mkdir -p /var/esempio
sudo nano /etc/cron.d/esempio
Dentro scrivo (minuto 11, ora 15, tutti i giorni, tutti i mesi, tutti i giorni della settimana, utente root):
11 15 * * * root echo ciao > /var/esempio/cron1.log
Salvo. Il comando scrive la parola ciao nel file indicato; potremmo usare cose molto più complicate, ma per ora ci basta. Intanto controlliamo che il file sia lì:
ls /etc/cron.d
cat /etc/cron.d/esempio
Alle 15:11 verifichiamo il risultato:
cat /var/esempio/cron1.log
Dentro c’è la parola ciao. Puoi lanciare qualunque comando di sistema o script Bash scritto da te: l’unico limite è la fantasia.
Operatori: intervalli, range ed elenchi
Oltre ai valori precisi puoi usare:
- lo slash (/) per gli intervalli ripetuti: */2 nel campo dei minuti vuol dire “ogni 2 minuti”;
- il trattino (-) per i range: 14-16 nel campo delle ore vuol dire per tutte le ore dalle 14 alle 16;
- la virgola (,) per gli elenchi: 4,6 nel campo del giorno della settimana vuol dire giovedì e sabato.
Mettiamoli insieme: eseguire il compito ogni 2 minuti, dalle 14 alle 16, ma solo il giovedì e il sabato. Questa volta usiamo >> per accodare al file invece di sovrascriverlo, così vediamo crescere l’elenco delle esecuzioni:
*/2 14-16 * * 4,6 root echo ciao >> /var/esempio/cron1.log
Salvando, il demone ricarica da solo la sua tabella. Per vedere cosa succede puoi seguire il file con tail -f:
tail -f /var/esempio/cron1.log
Nella puntata il primo log è comparso alle 15:16 di un sabato: l’ora 15 è nel range 14-16, il minuto 16 è divisibile per 2 e il sabato (giorno 6) è nell’elenco. Come vedi si possono creare regole anche molto complesse.
Qualche altro esempio, preso dalle note della puntata (il comando va sempre dopo i cinque campi):
1-30 * * * * /comando/da/eseguire
*/10 * * * * /comando/da/eseguire
30 * 1-7 * * /comando/da/eseguire
00 */2 15 * * /comando/da/eseguire
00 1-9/2 1 5 * /comando/da/eseguire
00 13 2,8,14 * * /comando/da/eseguire
30 13 1-15 4,10 * /comando/da/eseguire
*/30 13,20 * 1-7,9-12 1-5 /comando/da/eseguire
In ordine, significano:
- ogni minuto da 1 a 30 di ogni ora;
- ogni 10 minuti (00, 10, 20, 30, 40, 50);
- i primi sette giorni di ogni mese, ogni ora, al minuto 30;
- il quindicesimo giorno di ogni mese, ogni due ore;
- il primo maggio alle 1, 3, 5, 7 e 9;
- il 2, l’8 e il 14 di ogni mese alle 13:00;
- i primi quindici giorni di aprile e ottobre alle 13:30;
- nei giorni feriali, tutti i mesi tranne agosto, alle 13:00, 13:30, 20:00 e 20:30.
Un’attenzione particolare: se indichi sia il giorno del mese sia il giorno della settimana (entrambi diversi da asterisco), cron esegue il comando quando corrisponde l’uno OPPURE l’altro, non entrambi. Questa riga gira nei primi quindici giorni del mese e anche tutti i venerdì:
00 14,19 1-15 * 5 /comando/da/eseguire
Per ottenere “solo il venerdì tra l’1 e il 15” devi fare un test a parte sulla data, dentro il crontab o in uno script. Attenzione all’escape del carattere %, che nel crontab ha un significato speciale. Per esempio, mezzanotte della prima domenica del mese:
00 00 1-7 * * [ $(/bin/date '+\%u') -eq 7 ] \
&& /comando/da/eseguire
Variabili del crontab
Le variabili che puoi mettere in testa a un crontab:
- SHELL: se non assegnata, cron usa /bin/sh. Su Debian è dash: se lanci script Bash metti SHELL=/bin/bash;
- PATH: di default è /usr/bin:/bin. Cambialo se i tuoi comandi stanno altrove, o scrivi il percorso completo;
- LOGNAME e HOME: utente e home di chi esegue, non si cambiano;
- MAILTO: di default cron manda per mail l’output dei comandi all’utente proprietario. Con MAILTO=utente lo manda a lui (più utenti separati da virgola), con MAILTO=”” non manda niente.
Per gestire l’output di un singolo comando basta la redirezione:
00 3 1 7 * /comando/da/eseguire > /dev/null
00 3 1 7 * /comando/da/eseguire > /dev/null 2>&1
00 3 1 7 * /comando/da/eseguire >> /percorso/mio_file.log 2>&1
La prima scarta l’output normale e lascia la mail per i soli errori, la seconda scarta tutto, la terza accoda tutto a un tuo file di log.
I crontab degli utenti
Finora abbiamo parlato di cron di sistema, ma ogni utente ha la sua tabella, indipendente da quella di sistema. Non si modificano a mano i file in /var/spool: si usa il comando crontab. Prima cosa, elenco quello dell’utente corrente:
crontab -l
Se non ne hai ancora definito uno, dice che non c’è alcun crontab. Per modificarlo:
crontab -e
Si apre l’editor di sistema (nella puntata mcedit; dipende da EDITOR o VISUAL). Nota che manca la colonna dell’utente: ovviamente è l’utente proprietario del crontab. Scrivo una riga che gira ogni minuto:
* * * * * echo ciao >> /var/esempio/cron2.log
Salvo ed esco: crontab avvisa che ha installato il nuovo crontab. Controlliamo:
crontab -l
Dopo un minuto il file cron2.log contiene la scritta, e continuerà a ogni minuto:
cat /var/esempio/cron2.log
Dove si trovano i crontab degli utenti? In /var/spool:
sudo ls /var/spool/cron/crontabs
C’è un file col nome dell’utente, con dentro quello che hai visto con crontab -l.
Salvare, cancellare E importare
Per esportare (backup, o per portarlo su un’altra macchina):
crontab -l > cron-save.txt
Per rimuovere il crontab dell’utente:
crontab -r
Per importarlo di nuovo, passando il nome del file (attenzione: se c’è già un crontab viene sovrascritto):
crontab cron-save.txt
crontab -l
Da root puoi operare sul crontab di un altro utente con -u:
sudo crontab -u utente -l > usercrontab
sudo crontab -u utente usercrontab
E per non riempire il disco di log inutili, finito l’esperimento togli il crontab e i file di prova:
crontab -r
sudo rm /etc/cron.d/esempio
Chi puo’ usare crontab
Su Debian, di default, tutti gli utenti possono usare crontab. Puoi cambiarlo con due file: se esiste /etc/cron.allow, solo gli utenti elencati lì (uno per riga) possono usarlo; se esiste /etc/cron.deny, gli utenti elencati non possono. Se ci sono entrambi vale solo cron.allow. Root può sempre.
Esercizio
Scrivi un crontab utente che il giorno di Natale di ogni anno scriva Buon Natale in un file di una cartella del tuo sistema. Se vuoi esagerare, aggiungi una seconda riga che ti faccia gli auguri di buon compleanno. Se vuoi, raccontami nei commenti come l’hai risolto.
Conclusione
Ora sai creare file crontab, gestire i task pianificati e usare sia il cron di sistema sia quello per utente. Se ti interessano anacron o le sintassi avanzate di cron, fammelo sapere. Nel frattempo apri la tua Linux box e sperimenta: è il modo migliore per imparare.
Link e risorse
- il video su YouTube
- esempi e comandi della puntata su GitHub
- crontab(5), man page — il formato del file
- cron(8), man page — il demone cron
- crontab(1), man page — il comando crontab
- Cron sulla wiki di Arch — in inglese
- Crontab su Wikipedia — in italiano
Sostieni il canale
PER SOSTENERE IL CANALE BASTANO UN LIKE E UN’ISCRIZIONE!
ma se vuoi offrirmi un caffè, mi aiuterà a rimanere sveglio mentre registro i video 😁☕
clicca qui per scoprire come https://buymeacoffee.com/thelinuxnerd
questi link sono affiliati Amazon, acquistando i libri che ti consiglio sostieni il canale!
