Guida avanzata di scripting Bash: Un'approfondita esplorazione dell'arte dello scripting di shell | ||
---|---|---|
Indietro | Capitolo 10. Cicli ed alternative | Avanti |
Comandi inerenti al comportamento del ciclo
I comandi di controllo del ciclo break e continue [1] corrispondono esattamente ai loro analoghi degli altri linguaggi di programmazione. Il comando break interrompe il ciclo (esce), mentre continue provoca il salto all'iterazione (ripetizione) successiva, tralasciando tutti i restanti comandi di quel particolare passo del ciclo.
Esempio 10-20. Effetti di break e continue in un ciclo
#!/bin/bash LIMITE=19 # Limite superiore echo echo "Visualizza i numeri da 1 fino a 20 (saltando 3 e 11)." a=0 while [ $a -le "$LIMITE" ] do a=$(($a+1)) if [ "$a" -eq 3 ] || [ "$a" -eq 11 ] # Esclude 3 e 11. then continue # Salta la parte restante di questa particolare #+ iterazione del ciclo. fi echo -n "$a " # Non visualizza 3 e 11. done # Esercizio: # Perché il ciclo visualizza fino a 20? echo; echo echo Visualizza i numeri da 1 a 20, ma succede qualcosa dopo il 2. ################################################################## # Stesso ciclo, ma sostituendo 'continue' con 'break'. a=0 while [ "$a" -le "$LIMITE" ] do a=$(($a+1)) if [ "$a" -gt 2 ] then break # Salta l'intero ciclo. fi echo -n "$a " done echo; echo; echo exit 0 |
Il comando break può avere
un parametro. Il semplice break
conclude il ciclo in cui il comando di trova, mentre un
break N interrompe il ciclo di livello
N
.
Esempio 10-21. Interrompere un ciclo ad un determinato livello
#!/bin/bash # break-levels.sh: Interruzione di cicli. # "break N" interrompe i cicli al livello N. for cicloesterno in 1 2 3 4 5 do echo -n "Gruppo $cicloesterno: " #--------------------------------- for ciclointerno in 1 2 3 4 5 do echo -n "$ciclointerno " if [ "$ciclointerno" -eq 3 ] then break # Provate break 2 per vedere il risultato. # ("Interrompe" entrambi i cicli, interno ed esterno). fi done #--------------------------------- echo done echo exit 0 |
Il comando continue, come
break, può avere un parametro.
Un semplice continue interrompe
l'esecuzione dell'iterazione corrente del ciclo e dà
inizio alla successiva. continue N
salta tutte le restanti iterazioni del ciclo in cui si
trova e continua con l'iterazione successiva del
ciclo N
di livello superiore.
Esempio 10-22. Proseguire ad un livello di ciclo superiore
#!/bin/bash # Il comando "continue N", continua all'Nsimo livello. for esterno in I II III IV V # ciclo esterno do echo; echo -n "Gruppo $esterno: " # ---------------------------------------------------- for interno in 1 2 3 4 5 6 7 8 9 10 # ciclo interno do if [ "$interno" -eq 7 ] then continue 2 # Continua al ciclo di 2 livello, cioè il #+ "ciclo esterno". Modificate la riga precedente #+ con un semplice "continue" per vedere il #+ consueto comportamento del ciclo. fi echo -n "$interno " # 7 8 9 10 non verranno mai visualizzati. done # ---------------------------------------------------- done echo; echo # Esercizio: # Trovate un valido uso di "continue N" in uno script. exit 0 |
Esempio 10-23. Uso di continue N in un caso reale
# Albert Reiner fornisce un esempio di come usare "continue N": # --------------------------------------------------------- # Supponiamo di avere un numero elevato di job che devono essere #+ eseguiti, con tutti i dati che devono essere trattati contenuti in un #+ file, che ha un certo nome ed è inserito in una data directory. #+ Ci sono diverse macchine che hanno accesso a questa directory e voglio #+ distribuire il lavoro su tutte queste macchine. Per far questo, #+ solitamente, utilizzo nohup con il codice seguente su ogni macchina: while true do for n in .iso.* do [ "$n" = ".iso.opts" ] && continue beta=${n#.iso.} [ -r .Iso.$beta ] && continue [ -r .lock.$beta ] && sleep 10 && continue lockfile -r0 .lock.$beta || continue echo -n "$beta: " `date` run-isotherm $beta date ls -alF .Iso.$beta [ -r .Iso.$beta ] && rm -f .lock.$beta continue 2 done break done # I dettagli, in particolare sleep N, sono specifici per la mia #+ applicazione, ma la struttura generale è: while true do for job in {modello} do {job già terminati o in esecuzione} && continue {marca il job come in esecuzione, lo esegue, lo marca come eseguito} continue 2 done break # Oppure `sleep 600' per evitare la conclusione. done # In questo modo lo script si interromperà solo quando non ci saranno #+ più job da eseguire (compresi i job che sono stati aggiunti durante #+ il runtime). Tramite l'uso di appropriati lockfile può essere #+ eseguito su diverse macchine concorrenti senza duplicazione di #+ calcoli [che, nel mio caso, occupano un paio d'ore, quindi è #+ veramente il caso di evitarlo]. Inoltre, poiché la ricerca #+ ricomincia sempre dall'inizio, è possibile codificare le priorità #+ nei nomi dei file. Naturalmente, questo si potrebbe fare senza #+ `continue 2', ma allora si dovrebbe verificare effettivamente se #+ alcuni job sono stati eseguiti (in questo caso dovremmo cercare #+ immediatamente il job successivo) o meno (in quest'altro dovremmo #+ interrompere o sospendere l'esecuzione per molto tempo prima di #+ poter verificare un nuovo job). |
Il costrutto continue N è difficile da capire e complicato da usare, in modo significativo, in qualsiasi contesto. Sarebbe meglio evitarlo. |
[1] | Sono builtin di shell, mentre altri comandi di ciclo, come while e case, sono parole chiave. |