Le istruzioni di loop vengono utilizzate per forzare un programma a eseguire ripetutamente un'istruzione. L'istruzione eseguita è chiamata corpo del ciclo.
I cicli vengono eseguiti finché il valore di un'espressione di controllo non è 0. L'espressione di controllo può essere qualsiasi tipo di dati scalare.
Il linguaggio della shell fornisce anche diverse istruzioni di iterazione o loop. In questo articolo esaminiamo le istruzioni di looping fornite da bash utilizzando alcuni esempi.
Bash supporta i seguenti tre tipi di istruzioni di ciclo
- Ciclo per
- Durante il ciclo
- Fino al ciclo
Questo articolo fa parte della serie in corso di Bash Tutorial.
I loop possono essere nidificati. Come qualsiasi altro linguaggio di programmazione, bash supporta anche l'istruzione break per uscire dal ciclo corrente e l'istruzione continue per riprendere l'iterazione successiva dell'istruzione del ciclo.
Bash For Loop – Primo metodo
I cicli For vengono in genere utilizzati quando il numero di iterazioni è noto prima di entrare nel ciclo bash. Bash supporta due tipi di ciclo for. La prima forma di bash for loop è:
for varname in list do commands ##Body of the loop done
Nella sintassi sopra:
- for, in, do e done sono parole chiave
- Elenco è un elenco che contiene un elenco di elementi
- varname è qualsiasi nome di variabile Bash.
In questa forma, l'istruzione for esegue il comando racchiuso in un corpo, una volta per ogni elemento nell'elenco. L'elemento corrente dall'elenco verrà memorizzato in una variabile "varname" ogni volta che si esegue il ciclo. Questo varname può essere elaborato nel corpo del ciclo. Questo elenco può essere una variabile che contiene più parole separate da spazi. Se l'elenco non è presente nell'istruzione for, prende il parametro posizionale che è stato passato nella shell.
Esempio Bash For Loop 1. Decomprimi tutto il file zip
L'esempio seguente trova l'elenco dei file che corrispondono a "*.zip*" nella directory principale, crea una nuova directory nella stessa posizione in cui esiste il file zip e decomprimi il contenuto del file zip.
# cat zip_unzip.sh #! /bin/bash # Find files which has .zip for file in `find /root -name "*.zip*" -type f` do # Skip the extension .zip dirname=`echo ${file} | awk -F'.' '{print $1}'` # Create the directory mkdir $dirname # Copy the zip file cp ${file} ${dirname} cd $dirname # Unzip the zip file from newly created directory unzip ${dirname}/$(echo ${file##/*/}) done
- In questo esempio il comando find restituisce l'elenco dei file, da cui ogni file verrà elaborato in un ciclo.
- Per ogni elemento, crea la directory con il nome del file zip, copia il file zip nella directory appena creata e decomprime il file zip da lì.
- L'istruzione echo, echo ${file##/*/} ti fornisce solo il nome del file e non il percorso.
# ./zip_unzip.sh Archive: /root/test2/test2.zip extracting: t1/p extracting: t1/q extracting: t1/r extracting: t1/s extracting: t1/t extracting: t1/u extracting: t1/v Archive: /root/test1/test1.zip extracting: t/a extracting: t/b extracting: t/c extracting: t/d extracting: t/e
Simile al ciclo Bash, Awk fornisce anche ciclo for e ciclo while, come abbiamo discusso nel nostro articolo Awk While e For Loop.
Bash For Loop – Secondo metodo
La seconda forma di ciclo for è simile al ciclo for nel linguaggio di programmazione 'C', che ha tre espressioni (inizializzazione, condizione e aggiornamento).
for (( expr1; expr2; expr3 )) do commands done
- Nella precedente bash per la sintassi dei comandi, prima della prima iterazione, viene valutato expr1. Questo è solitamente usato per inizializzare le variabili per il ciclo.
- Tutte le istruzioni tra do e done vengono eseguite ripetutamente finché il valore di expr2 è TRUE.
- Dopo ogni iterazione del ciclo, viene valutata expr3. Di solito viene utilizzato per incrementare un contatore di loop.
L'esempio seguente genera il numero n di numeri casuali.
Bash per esempio 2. Genera n numeri casuali
$ cat random.sh #! /bin/bash echo -e "How many random numbers you want to generate" read max for (( start = 1; start <= $max; start++ )) do echo -e $RANDOM done $ ./random.sh How many random numbers you want to generate 5 6119 27200 1998 12097 9181
Nel frammento di codice sopra, il ciclo for genera il numero casuale al massimo numero di volte. RANDOM è una funzione bash interna che restituisce un numero intero casuale ad ogni chiamata.
Bash in loop
Un'altra istruzione di iterazione offerta dal linguaggio di programmazione della shell è l'istruzione while.
Syntax: while expression do commands done
Nella precedente sintassi del ciclo while:
- while, do, done sono parole chiave
- L'espressione è qualsiasi espressione che restituisce un valore scalare
- L'istruzione While provoca l'esecuzione di un blocco di codice mentre un'espressione condizionale fornita è vera.
Bash While Esempio 3. Scrivi i contenuti in un file
L'esempio seguente legge i dati dallo stdout e li scrive in un file.
$ cat writefile.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to create" read file while read line do echo $line >> $file done $ sh writefile.sh Enter absolute path of the file name you want to create /tmp/a while for until $ cat /tmp/a while for until
L'esempio sopra, legge il nome del file dall'utente, legge le righe di dati da stdin e aggiunge ogni riga a un determinato nome file. Quando EOF entra, la lettura fallirà, quindi il ciclo finisce lì.
Se stai scrivendo molti script bash, puoi usare Vim editor come Bash IDE usando il plug-in Vim bash-support come abbiamo discusso in precedenza.
Bash While Esempio 4. Leggi il contenuto di un file
Nell'esempio precedente, legge i dati da stdout e li scrive in un file. In questo esempio, legge il file
contenuto e lo scrive in uno stdout.
$ cat read.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to read" read file exec <$file # redirects stdin to a file while read line do echo $line done $ ./read.sh Enter absolute path of the file name you want to read /tmp/a while for until
In questo esempio, ottiene il nome del file da leggere e, utilizzando exec, reindirizza lo stdin a un file. Da quel momento in poi, tutto lo stdin viene da quel file, piuttosto che dalla tastiera. read comando legge la riga da stdin, quindi mentre loop legge lo stdin, finché non si verifica EOF.
Bash fino al loop
L'istruzione until è molto simile nella sintassi e nella funzione all'istruzione while. L'unica vera differenza tra i due è che l'istruzione until esegue il suo blocco di codice mentre la sua espressione condizionale è falsa, e l'istruzione while esegue il suo blocco di codice mentre la sua espressione condizionale è vera.
syntax: until expression do commands #body of the loop done
Nella precedente sintassi bash fino a:
dove until, do, done sono le parole chiave
espressione qualsiasi espressione condizionale
Bash fino all'esempio 5. Monitora il file di registro
Questo esempio monitora la dimensione del file di log, una volta che la dimensione del file di log raggiunge i 2000 byte, prende la copia di quel file di log.
$ cat monitor.sh file=/tmp/logfile until [ $(ls -l $file | awk '{print $5}') -gt 2000 ] do echo "Sleeping for next 5 seconds" sleep 5 done date=`date +%s` cp $file "$file-"$date.bak $ ./monitor.sh Sleeping for next 5 seconds Sleeping for next 5 seconds $ ls -l /tmp/logfile* -rw-r--r-- 1 sss sss 2010 Jun 24 12:29 logfile -rw-r--r-- 1 sss sss 2005 Jun 24 16:09 logfile-1277474574.bak
L'istruzione until continua ad eseguire il corpo del ciclo, finché la condizione non diventa vera. In questo esempio la condizione è la dimensione del file maggiore di 2000 byte, quindi copia il file una volta che raggiunge i 2000 byte.
Inoltre, assicurati di fare riferimento ai nostri precedenti esempi di Bash Array.
Bash fino all'esempio 6. Aspettando che la macchina si avvii
Questo esempio viene utilizzato per attendere che la macchina si avvii prima di eseguire un ssh su quella macchina. L'istruzione fino al ciclo termina solo quando il ping fornisce le risposte.
$ cat mac_wait.sh #! /bin/bash read -p "Enter IP Address:" ipadd echo $ipadd until ping -c 1 $ipadd do sleep 60; done ssh $ipadd $./mac_wait.sh Enter IP Address:192.143.2.10 PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data. --- 192.143.2.10 ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data. 64 bytes from 192.143.2.10: icmp_seq=1 ttl=64 time=0.059 ms --- 192.143.2.10 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.059/0.059/0.059/0.000 ms The authenticity of host '192.143.2.10 (192.143.2.10)' can't be established. Are you sure you want to continue connecting (yes/no)? yes
Fino a loop è abbastanza utile sulla riga di comando, come un modo per aspettare che si verifichino determinati eventi.