Pianificare comandi su GNU/Linux con i cron job

23/04/2021

Nei sistemi operativi Unix e Unix-like esiste un servizio, in gergo demone, chiamato crond, il quale consente di pianificare comandi, consentendone l’esecuzione automatica in modalità periodica, su determinate condizioni e/o all’avvio del sistema operativo.

Definiremo cron job appunto l’operazione da eseguire. La pianificazione dei comandi avviene mediante un apposito file chiamato crontab, il quale contiene proprio la lista dei cron job e le correlate informazioni riguardanti il periodo di esecuzione. Inoltre, ciascun utente nel sistema può avere il suo crontab, così come esistono dei crontab a livello di sistema.

Vedremo che gestire un crontab non è un’operazione complicata, anzi tutt’altro. Ad ogni modo è bene conoscere un paio di nozioni fondamentali al fine di ottenere i risultati sperati.

Installare cron

In genere, tutte le distribuzioni Linux includono il demone cron, anche se alcune distro preferiscono usare i timer di systemd, che vedremo in un altro video. Intanto concentriamoci sui cronjob che sono comodi e semplici.

  • Su Ubuntu e derivate, cron è già installato, per cui non è necessario fare altro;
  • Su Arch Linux e derivate, cron va installato a parte, mediante i comandi:
pacman -S cronie
sudo systemctl enable cronie
sudo systemctl start cronie

Per le altre distro, qualora cron non fosse presente, consultate la documentazione correlata.

Struttura di un job

Ciascun job sarà rappresentato nel seguente modo:

#  .---------------- [m]inute: minuto (0 - 59) 
#  |   .------------- [h]our: ora (0 - 23)
#  |   |   .---------- [d]ay of month: giorno del mese (1 - 31)
#  |   |   |    .------- [mon]th: mese (1 - 12) OPPURE jan,feb,mar,apr... 
#  |   |   |    |    .---- [w]eek day: giorno della settimana (0 - 6) (domenica=0 o 7)  OPPURE sun,mon,tue,wed,thu,fri,sat 
#  |   |   |    |    |
# [m] [h] [d] [mon] [w]  [comando da eseguire]

In particolare:

  • [m] indica il minuto in cui eseguire l’operazione. Va indicato in forma numerica, chiaramente, in un intervallo compreso tra 0 e 59, inclusi entrambi;
  • [h] indica l’ora in cui eseguire l’operazione. Va indicata in un intervallo compreso tra 0 e 23, entrambi inclusi;
  • [d] indica il giorno del mese in cui l’operazione deve essere eseguita. Va indicato in un intervallo compreso tra 1 e 31, entrambi inclusi;
  • [mon] indica il mese in cui eseguire l’operazione. Può essere indicato, sia in forma numerica in un intervallo compresso tra 1 e 12 (entrambi inclusi), che in forma letterale, usando le tre lettere iniziali dei mesi in inglese. Ad es. jan per gennaio, feb per febbraio, ecc;
  • [w] indica il giorno della settimana. Può essere indicato in forma numerica in un intervallo compreso tra 0 e 6 oppure 1 e 7 (entrambi inclusi). Ciò è principalmente legato al fatto che in alcuni paesi, principalmente di origine latina, come l’Italia, domenica è l’ultimo giorno della settimana, mentre nei paesi principalmente anglosassoni, domenica è il primo giorno della settimana, che per Unix è il giorno 0. In alternativa è possibile usare la forma letterale usando le tre lettere iniziali delle settimane in inglese. Ad es. mon per lunedì, tue per martedì, ecc.
  • Infine vi è il comando da eseguire, il quale consiste in un semplicissimo comando Unix. Più comandi possono essere inseriti nello stesso cron job, semplicemente:
    • Separandoli col punto e virgola (;);
    • Qualora il successivo fosse dipendente dal precedente, dal doppio ampersand (&&). In quest’ultimo caso, qualora il primo comando dovesse fallire, il secondo non sarà eseguito.

Fatta eccezione per il comando, in uno o più campi è possibile inserire l’asterisco (*) al posto del valore tipicamente accettato. L’asterisco indica che il valore di quel campo è irrilevante per il job e che possono essere considerati tutti i valori per esso. Ad esempio, l’asterisco nel campo dell’ora significa: qualunque ora va bene per l’esecuzione del job.

Esempio stringa

Supponendo che l’intenzione sia quella di aggiornare la cache dei repository del sistema operativo alle ore 0:00 di ogni sabato, si potrebbe inserire nel cron tab una stringa del seguente tipo:

0 0 * * 6 /usr/bin/pacman -Syy
  • Il campo dell’minuto avrà chiaramente 0, così come il campo dell’ora. Nel complesso si indicano appunto le 0:00;
  • Al posto del giorno del mese è stato inserito *****, appunto per indicare che qualunque giorno va bene per eseguire l’operazione. Lo stesso vale per il mese;
  • Il giorno della settimana sarà chiaramente 6, essendo sabato il sesto giorno.

In sintesi questo significa: ogni sabato a mezzanotte esegui il comando pacman -Syy, a prescindere dal giorno e dal mese.

Nota

Quando in una stringa è presente, sia il giorno del mese, che il giorno della settimana, l’esecuzione del job avverrà quando almeno una delle due condizioni si verifica. Ad esempio:

0 0 1 * 6 /usr/bin/pacman -Syy

Significa che l’aggiornamento sarà eseguito ogni primo del mese oppure ogni sabato. Quindi non significa che sarà eseguito il primo del mese se viene di sabato.

Operatori valori multipli

Quanto visto finora è un primo approccio alla sintassi da usare nel crontab. Vediamo ora un attimino di complicare le cose, aggiungendo dei valori multipli, ovvero, la possibilità di associare ad ogni campo più di un valore, che corrisponderanno appunto ai periodi in cui deve essere eseguito il job. In particolare, la sintassi prevede l’uso di tre operatori:

  • L’operatore virgola (,): serve a specificare una lista di valori. Ad esempio, la lista 1,2,3,4,5 nel campo ora sta ad indicare che il job deve essere eseguito per ciascuna ora indicata; L’operatore trattino (-): serve a specificare un intervallo di valori, incluso l’inizio e la fine. Ad esempio, l’intervallo 1-5 nel campo ora sta ad indicare che il job deve essere eseguito per ciascuna ora dell’intervallo indicato, incluso 1 e 5;
  • L’operatore asterisco (*): già visto prima, serve a considerare tutti i valori per quel determinato campo. Ho preferito tuttavia introdurlo subito così da potervi fare immediatamente un esempio più pratico;
  • L’operatore slash (/): permette di saltare un certo numero di valori, a partire da 0. Ad esempio, scrivere */3 nel campo ora, significa che il job deve essere eseguito per tutti i valori multipli di 3, incluso lo zero, quindi a mezzanotte, alle tre, alle sei, alle nove, alle dodici, alle quindici, ecc.

Esempio

Supponiamo di voler aggiornare la cache dei repository del sistema operativo ogni tre ore. Il cron andrà scritto come:

0 */3 * * * /usr/bin/pacman -Syy

Questo significa: al minuto zero, ogni tre ore, di qualsiasi giorno, mese e settimana, aggiorna i repository. Si osservi che ho inserito il percorso assoluto al file eseguibile di pacman, appunto /usr/bin/. Questo perchè nel terminale non ne abbiamo bisogno, in quanto l’ambiente sa già che gli eseguibili si trovano li. Tuttavia, in base alla distribuzione, ciò può non valere per il crontab, per cui è preferibile usare includere il percorso. -Syy è invece è un’opzione di pacman, per cui rimane com’è.

Esempio 2

Supponiamo che gli aggiornamenti remoti dei repo della nostra distribuzione avvengano principalmente il sabato e la domenica, per cui vogliamo che questa operazione sia eseguita soltanto per tali giorni. Dovremo scrivere:

0 */3 * * 6,7 /usr/bin/pacman -Syy

O in alternativa:

0 */3 * * 6-7 /usr/bin/pacman -Syy

Stringhe speciali

Esistono inoltre delle stringhe speciali, le quali permettono, in alcuni casi, di semplificare la sintassi vista precedentemente, chiaramente a discapito della personalizzazione. Le stringhe sono:

  • @reboot: permette di eseguire il cron una volta all’avvio del sistema operativo;
  • @yearly: permette di eseguire il cron una volta all’anno. Equivale a scrivere 0 0 1 1 * (mezzanotte del primo di gennaio);
  • @monthly: permette di eseguire il cron una volta al mese. Equivale a scrivere 0 0 1 * * (mezzanotte del primo di qualunque mese);
  • @weekly: permette di eseguire il cron una volta alla settimana. Equivale a scrivere 0 0 * * 0 (mezzanotte di qualunque giorno e mese, di domenica);
  • @daily: permette di eseguire il cron una volta al giorno. Equivale a scrivere 0 0 * * * (mezzanotte di qualunque giorno, mese e settimana);
  • @hourly: permette di eseguire il cron ogni ora. Equivale a scrivere 0 * * * * (minuto zero di qualunque ora del giorno).

Esempio

Supponendo quindi di voler aggiornare i repository ogni volta che parte il sistema operativo, il crontab conterrà la stringa:

@reboot /usr/bin/pacman -Syy

Stop, non bisognerà fare altro.

Modificare il crontab

Ora che abbiamo visto com’è fatta la stringa di un cron job, andiamo a vedere com’è fatto il crontab. Come accennato all’inizio, il crontab esiste a livello sistema, così come a livello utente. Chiaramente quest’ultimo potrà eseguire comandi limitati ai suoi privilegi, mentre a livello sistema si agirà come root.

Livello sistema

Per modificare il crontab a livello sistema è sufficiente digitare il comando:

sudo crontab -e

O in alternativa:

su
crontab -e

Il comando aprirà dunque l’editor di testo in cui andare a inserire le stringhe usando la sintassi vista precedentemente.

Modifica editor di testo

Ad esempio, in Arch Linux l’editor di testo predefinito per il crontab è vi. Tuttavia può essere scelto digitando:

sudo EDITOR=editor crontab -e

Esempio

Tornando all’esempio dell’aggiornamento repository ad ogni avvio, possiamo scrivere:

@reboot /usr/bin/pacman -Syy

Essendo quest’ultimo un comando che richiede i massimi privilegi, è obbligatorio inserirlo nel crontab di sistema.

A questo punto, salviamo le modifiche e usciamo. Così facendo, il crontab a livello di sistema è configurato per aggiornare i repository ogni volta all’avvio.

Livello utente

Il crontab per utente può essere modificato scrivendo:

crontab -e

Ancora una volta, possiamo scegliere l’editor di testo:

EDITOR=editor crontab -e

In alternativa, da utente root è possibile modificare i crontab altrui con:

crontab -u nomeutente -e

Si aprirà sempre un editor di testo, ma questa volta i job che andremo ad inserire verranno automaticamente eseguiti a nome dell’utente corrente. Chiaramente, qui non sarà possibile eseguire job a nome di altri utenti del sistema operativo.

Visualizzare schedulazione

Dopo ogni modifica è possibile verificare se il crontab è stato letto correttamente mediante i comandi:

sudo crontab -l # Per l'utente root
crontab -l # Per l'utente corrente

Utilità del crontab

Schedulare attività mediante il crontab è molto utile, soprattutto per eseguire operazioni che riguardano i backup periodici di file che risiedono nel sistema operativo.

Backup tramite rsync

Ad esempio, supponendo di voler fare il backup della nostra cartella home ogni fine settimana in un hard disk montato nel percorso /media/pippo/backup, si potrebbe scrivere nel crontab utente corrente:

0 0 * * 7 /usr/bin/rsync -axv /home/pippo/ /media/pippo/backup

Eseguire script python

Un altro esempio potrebbe essere quello di eseguire degli script python all’avvio, usando la sintassi:

@reboot /usr/bin/python /home/pippo/scripts/boot.py

Conclusione

Dunque, abbiamo visto com’è possibile schedulare operazioni su GNU/Linux mediante uno strumento semplice e potente. Per questo video è tutto, grazie per la visione. Vi invito a guardare il video sul canale YouTube per ulteriori dettagli.