5 I cicli bash: While, Until, For
i cicli ci permettono di ripetere l’esecuzione di porzioni di codice per un certo numero di volte, fino a quando una determinata condizione non viene raggiunta oppure fintanto che non vengono iterati gli elementi di un array, di una cartella o righe di files.
Bash fornisce 3 tipi di loops:
- While : Continua l’esecuzione del ciclo fino a quando la condizione del loop rimane vera
- Until : Fa l’inverso, continua ad iterare fino a quando la condizione del loop rimane falsa
- For : Il ciclo for è più compatto perchè inizializza una variabile temporanea e usando il suo incremento direttamente nella condizione
Facciamo un esempio con while
flag=0 while [ $flag -le 10 ]; do echo "Flag ora vale $flag" let flag+=1 done
La variabile flag vale zero, fintanto che la variabile flag è minore o uguale che si abbrevia con lower egual ( le ) a 10, stampo il valore.
Per incrementare uso flag+=1 il simbolo + dopo il nome della variabile seguito dall’uguale, incrementa il valore della quantità specificata dopo l’uguale. flag+=1 è l’abbreviazione di flag=flag+1 . Per incrementare di una sola unità si può usare anche il doppio più ( ++ ) flag++.
Per uscire da un loop possiamo utilizzare il comando break, interrompiamolo quando flag vale 5
flag=0 while [ $flag -le 10 ]; do echo "Flag ora vale $flag" let flag+=1 if [ $flag -eq 5 ]; then break fi done
il comando break interrompe il loop e lo script continua, qualora volessimo saltare una particolare iterazione dovremmo utilizzare la keyword continue, scriviamo è pari quando i numeri divisi per zero non hanno resto
flag=0 while [ $flag -le 10 ]; do echo "Flag ora vale $flag" let flag+=1 if [ $((flag%2)) -eq 0 ]; then printf "\t$flag è pari\n" else continue fi done
Per utilizzare lo stesso codice con until dovremmo modificare la condizione minore o uguale ( -le ) con maggiore di ( gt )
until [ $flag -gt 10 ]; do
Il ciclo viene eseguito fintanto che la condizione che flag è maggiore di 10 non viene soddisfatta
for
for item in {1..10} do echo "Item: $item" done
In questo caso item è una variabile temporanea disponibile solamente nel ciclo for. La condizione da verificare si mette tra parentesi graffe dopo la keyword in
Un loop infinito può essere utilizzato per mantenere l’esecuzione dello script attiva, magari fino a quando una certa condizione viene raggiunta per poi uscire con un break
while true do tail -f /var/log/apache2/access_log sleep 1 done
Questo è un esempio che viene fatto per monitorare i log di connessione web tramite il server web apache, il percorso della cartella potrebbe variare a seconda delle distribuzioni o dei server web.
Con il comando tail -f vengono lette le ultime 10 righe del file di log. Potrebbe essere utile salvare una parte del file di log in un altro file se alcune condizioni fossero incontrate, per poi rifattorizzare i contenuti del log.
In tutti quei casi dove avvengono comunicazioni asincrone, c’è sempre una parte di software che deve rimanere in ascolto e attendere un qualche evento.
Completiamo la parte dello script abbandonato nella lezione precedente applicando le nuove nozioni apprese dai loops ecco il codice che avevamo scritto
unction 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..." if [ ! -d "$HOME/logs/$month_name" ]; then mkdir "$HOME/logs/$month_name" fi 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 elif [ "$confer" == "n" ]; then echo "[i] Nessuna operazione, uscita" fi } if [[ -n "$1" && -n "$2" ]]; then if [ ! -d "$HOME/logs" ]; then mkdir $HOME/logs fi generate_logs $1 $2 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
definiamo il numero di logs che vogliamo creare definendo l’argomento tramite riga di comando. Un file di testo verrà creato per ogni giorno compreso nell’intervallo temporale dichiarato
else echo "[i] Directory vuota, generiamo i logs" while [ $days -gt 0 ]; do touch $HOME/logs/$month_name/${days}.txt let days-- done fi
Con questo while dico: fino a che la variabile days è maggiore di zero, genero files dentro la cartella month_name tramite il comando touch. Supponendo di passare come parametri July 31, la variabile days all’inizio avrà il valore 31 e il primo file generato dentro la cartella July sarà 31.txt. Tramite il decremento di una unità let days–, il secondo sarà 30.txt, il terzo 29.txt e così via fino al raggiungimento del valore zero
./create_logs.sh july 31
Potete provare lo script su altri mesi, se si prova su un mese già creato, lo script si interrompe avvisando che la cartella esiste e non è vuota.
Un altra forma compatta da usare con il for è quella di utilizzare le doppie parentesi tonde per racchiudere la condizione
for (( i=1; i <= 10; i++ )); do echo $I done