4 Condizionali in bash (if / else / case)

Come abbiamo visto nella precedente lezione, i costrutti condizionali if else determinano delle condizioni da rispettare per eseguire determinate operazioni.

Le condizioni da rispettare devono essere racchiuse tra parentesi quadre [ ] seguite dalla keyword then su un altra riga oppure sulla stessa riga, ma divise con un punto e virgola..

È obbligatorio aggiungere uno spazio tra le parentesi e le condizioni.

if [ "test" == "test"]

L’if si traduce con se, quindi se la stringa test è uguale == a test esegui qualcosa

if [ "test" == "test"]
then
  echo "true"
else
  echo "false"
fi 

l’ else si traduce con altrimenti, quindi se la condizione non è vera eseguo altro.

La keyword fi sta ad indicare la fine della condizione if.

Oltre a if e then ci sono altri operatori condizionali, non è necessario ricordarli tutti, basta cercare conditional expression nel manuale di bash. Esistono operatori per verificare se esiste un file, una cartella, se ha una certa grandezza, se sia vuoto …. Questi operatori sono utili per creare script che eseguono operazioni su files e cartelle, per dimostrazione sull’uso di questi operatori e per introdurre all’uso di if else annidati, creiamo uno script che genererà files di log per ogni giorno del mese.

if [ -d "$HOME/logs" ]; then
  echo "La directory esiste"
  else
    echo "La directory non esiste"
fi

verifichiamo se nella cartela home esiste la directory logs, miglioriamo il codice negando con l’operatore NOT ( ! ) la condizione e se logs non esiste la creiamo

if [[ -n "$1" && -n "$2" ]]; then
  
if [ ! -d "$HOME/logs" ]; then
  mkdir $HOME/logs
fi

Nella prima riga verifichiamo che i parametri stringa passati dalla riga di comando siano maggiori di zero con l’opzione -n. Aggiungiamo la parte di help per invitare l’utente a vedere le opzioni.

if [[ -n "$1" && -n "$2" ]]; then

if [ ! -d "$HOME/logs" ]; then
  mkdir $HOME/logs
fi

elif [ "$1" == "-h" ]; then
    echo "Usa:"
    echo "./create_logs.sh <month_name> <days_to_generate>"
    echo "Info:"
    echo -e "Crea directory chiamata $HOME/logs/<month_name>"
    echo -e "Generati <days_to_generate> log text files contenenti to-do liste"
  else
    echo "Scrivi .create_logs.sh -h per la guida"
fi

Quando vi sono troppi if annidati si corre il rischio di creare confusione nel codice, è più conveniente creare una o più funzioni che si occupano delle operazioni da eseguire. Creiamo la funzione generate_logs

function generate_logs {
    local month_name=$1
    local days=$2
    echo "La directory $HOME/logs/$month_name sarà creata"
    echo "conterrà $days giorni di testo"
    printf "è corretto? [y/n]"
}

aggiungiamo la logica di conferma che legge l’input dell’utente, in modo che se sbagliassimo a digitare, non verranno create directory e files sbagliati. Questo può essere fatto tramite il comando read che legge l’input dell’utente

function generate_logs {
    local month_name=$1
    local days=$2
    local confirm
    echo "La directory $HOME/logs/$month_name sarà creata"
    echo "conterrà $days giorni di testo"
    printf "è corretto? [y/n]"

    read confirm

    if [ "$confirm" == "y" ]; then
      echo "[i] Controllo se i files precedenti esistono..."
      elif [ "$confer" == "n" ]; then
        echo "[i] Nessuna operazione, uscita"
    fi
}

adesso controlliamo se la directory esiste e se no la creiamo

read confirm

if [ "$confirm" == "y" ]; then
  echo "[i] Controllo se i files precedenti esistono..."

  if [ ! -d "$HOME/logs/$month_name" ]; then
    mkdir "$HOME/logs/$month_name"

Per creare i vari files coi giorni dei logs, bisognerà utilizzare i loop che vedremo più avanti. Per il momento ci limitiamo solo a controllare se la directory è vuota e se non lo fosse stoppiamo il flusso

if [ $(ls $HOME/logs/$month_name | wc -l) -ne 0 ]; then
  echo "[!] La cartella non è vuota! Annullo"
  exit 

Il controllo verifica se il comando ls eseguita nella directory mouth_name non sia uguale a zero. Qualora ci fosse anche un solo file nella cartella lo script bloccherebbe l’esecuzione.

if [ $(ls $HOME/logs/$month_name | wc -l) -ne 0 ]; then
  echo "[!] La cartella non è vuota! Annullo"
  exit
  else 
    echo "[i] Directory vuota, generiamo i logs"
fi

ok interrompiamo lo script che continueremo nella prossima lezione grazie all’introduzione dei comandi di loop, per dedicarci ora ad un altro costrutto condizionale.

case

Il comando case è un modo più compatto di eseguire delle istruzioni if else. Creiamo uno script che legge l’input dell’utente appena lo script sarà eseguito.

echo "Scegli un numero da 1 a 3. Premi q per chiudere."
read input

case $input in
1) echo "Hai scelto 1" ;;
2) echo "Hai scelto 2" ;;
3) echo "Hai scelto 3" ;;
q|Q) echo "Chiusura" ;;
*) echo "Non esiste" ;;

esac

Il doppio punto e virgola ( ; ; ) istruisce il costrutto che la parte then è conclusa. se l’utente digita l’opzione 1 stampa Hai scelto 1, uguale per 2 e 3 mentre per q OR Q stampa Chiusura, per tutto il resto stampa Non esiste.

L’inverso della parola case è esac e serve per chiudere il costrutto.

Testare il funzionamento…

Ora lo trasformeremo in un menu interattivo usando la ricorsione dentro una funzione

function menu {

  echo "Scegli un numero da 1 a 3. Premi q per chiudere."
  read input
  case $input in
  1) echo "Hai scelto 1"
    menu ;;
  2) echo "Hai scelto 2"
    menu ;;
  3) echo "Hai scelto 3"
    menu ;;
  q|Q) echo "Chiusura"
  exit ;;
  *) echo "Non esiste"
    menu ;;

esac
}

clear
menu

Ogni volta che un’opzione viene scelta, viene rilanciata la funzione menu, tranne che nell’uscita exit premuta da q. Il comando clear pulisce lo schermo della console appena lo script viene eseguito.

L’istruzione case è un’ottima scelta per semplificare la lettura se si presentano troppi if else annidati. Il menu interattivo implica una buona scelta di utilizzo del comando case.