Praticamente tutti i linguaggi di programmazione possiedono il concetto di ciclo: se si vuole ripetere un'azione venti volte, non c'è bisogno di scrivere ripetutamente lo stesso codice, magari modificandolo leggermente ogni volta. Utilizzare un ciclo consente di evitare proprio questo tipo di problema. Anche in Bash è possibile utilizzare i classici costrutti for
e while
come nei più classici linguaggi di programmazione.
Cicli for
Un ciclo for
itera una serie di valori finché la lista non si esaurisce:
for i in 1 2 3 4 5
do
echo "Numero $i"
done
Eseguendo lo script precedente, la variabile $i
assume ciascuno dei valori indicati dopo la parola chiave in
nello stesso ordine; i valori assunti possono essere di qualsiasi tipo, come si vede nell'esempio che segue:
for i in 1 2 topolino pippo 3 pluto
do
echo "i ha valore $i"
done
Per scorrere una lista di numeri interi è possibile anche usare la scorciatoia {1..10}
, che in questo caso specifico corrisponde allo scrivere 1 2 3 4 5 6 7 8 9 10
. Bash offre anche una sintassi alternativa per specificare cicli for
su liste di numeri interi, derivata da quella più diffusa e basata su C:
#!/bin/bash
for (( i = 0 ; i <= 20 ; i += 2 )) ; do
echo "i ha valore $i"
done
Questo ciclo for
usa tre diverse espressioni aritmetiche, separate da ;
(e non da ,
poiché sono tre espressioni separate, non semplici sotto-espressioni). La prima rappresenta l'inizializzazione, che viene eseguita prima che il ciclo inizi. La seconda è l'espressione di test, valutata prima di ogni potenziale iterazione del ciclo (inclusa la prima): se vale 0
(falso), il ciclo termina. La terza è l'espressione di conteggio e viene eseguita alla fine di ogni iterazione. Utilizzando questa nuova sintassi e quella che abbiamo visto usare per specificare espressioni aritmetiche, è possibile definire cicli su sequenze di numeri arbitrarie: nel seguente esempio la sequenza di valori stampata corrisponde ai primi 10 elementi della successione di Fibonacci.
#!/bin/bash
for (( i = 1 , j = 1 ; i <= 34 ; i += j, j += i )) ; do
echo -n "$i" "$j "
done
echo
Cicli while ed until
Un costrutto più flessibile del for
per definire cicli è il while
: è simile al costrutto if
che abbiamo visto nella sezione precedente, ma a differenza di quest'ultimo ripete i comandi fino a che la condizione specificata continua ad essere valutata come vera. Ad esempio, supponiamo di voler attendere finché il file attesa.txt venga eliminato. Un possibile approccio è quello di attendere per alcuni secondi (cioè non fare niente), per poi controllare se il file esiste ancora, ripetendo ciò continuamente in questo modo:
while [[ -e attesa.txt ]] ; do
sleep 3 # "dormi" per tre secondi
done
Un modo alternativo ma altrettanto valido è quello di usare il ciclo until
, che funziona in maniera simile al while
, ma nel modo inverso: esso infatti, continua ad eseguire i comandi fintantoché la condizione specificata è false, e termina nel momento in cui essa risulta vera. Ad esempio, se si volesse attendere fintantochè il file procedi.txt
venga creato, si potrebbe utilizzare il seguente script:
until [[ -e procedi.txt ]] ; do
sleep 3 # "dormi" per tre secondi
done
Ovviamente, si otterrebbe il medesimo risultato utilizzando il ciclo while
e negando (!
) la condizione contenuta nel comando test, ma in alcuni casi impiegare l'until
potrebbe migliorare la leggibilità del codice.
Utilizzare il ciclo while
è molto utile quando si vuol mantenere uno script in esecuzione finchè l'utente non decida di interromperlo, in questo modo:
echo "Inserisci un messaggio (esci per uscire)"
while [[ $INPUT != "esci" ]]
do
read INPUT
echo "Hai digitato: $INPUT"
done
Infine, esistono alcune situazioni particolari in cui non è possibile specificare una condizione chiara e prefissata da testare ad ogni ciclo while
, perciò la maggior parte dei linguaggi di programmazione offre la possibilità di definire cicli senza condizione che vengono eseguiti all'infinito. In Bash il simbolo :
viene valutato sempre come vero, perciò utilizzarlo come condizione di un ciclo while
impone a quest'ultimo di eseguire le istruzioni in esso contenute all'infinito. L'unico modo per interrompere l'esecuzione a livello di codice è quello di utilizzare il comando break
, che ha l'effetto di interrompere immediatamente il ciclo che lo contiene. Alla luce di questo, possiamo riscrivere l'esempio precedente in questo modo:
#!/bin/bash
echo "Inserisci un messaggio (esci per uscire)"
while :
do
read INPUT
if [[ $INPUT = "esci" ]] ; then
break
fi
echo "Hai digitato: $INPUT"
done