Come scrivo un ciclo for in bash


Risposte:


103

Da questo sito :

for i in $(seq 1 10);
do
    echo $i
done

10
Vale la pena ricordare che l'intervallo specificato qui è inclusivo . Con questo, voglio dire che vedrai l'intero intervallo (da 1 a 10) stampato sulla console.
Jamie


34

La bash forconsiste in una variabile (l'iteratore) e un elenco di parole in cui l'iteratore, beh, itererà.

Quindi, se hai un elenco limitato di parole, inseriscile nella seguente sintassi:

for w in word1 word2 word3
do
  doSomething($w)
done

Probabilmente vuoi iterare su alcuni numeri, quindi puoi usare il seqcomando per generare un elenco di numeri per te: (da 1 a 100 per esempio)

seq 1 100

e usalo nel ciclo FOR:

for n in $(seq 1 100)
do
  doSomething($n)
done

Nota la $(...)sintassi. È un comportamento bash, ti consente di passare l'output da un comando (nel nostro caso da seq) a un altro (il for)

Questo è davvero utile quando devi iterare su tutte le directory in un percorso, ad esempio:

for d in $(find $somepath -type d)
do
  doSomething($d)
done

Le possibilità sono infinite per generare le liste.


2
Buona risposta, ma potresti voler includere for ((i = 0; i <MAX; i ++)); fare qualcosa ($ i); variante fatta pure. Penso che questo sia generalmente preferito alla variante for i in $ (seq 0 MAX) poiché quest'ultima genererà prima tutti i numeri da 0 a MAX prima di eseguire effettivamente il ciclo.
mweerden

30

Bash 3.0+ può utilizzare questa sintassi:

for i in {1..10} ; do ... ; done

..che evita di generare un programma esterno per espandere la sequenza (come seq 1 10).

Ovviamente, questo ha lo stesso problema della for(())soluzione, essendo legato a bash e persino a una versione particolare (se questo ti interessa).


14

Prova la guida bashintegrata:


$ help for

for: for NAME [in WORDS ... ;] do COMMANDS; done
    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    Equivalent to
        (( EXP1 ))
        while (( EXP2 )); do
            COMMANDS
            (( EXP3 ))
        done
    EXP1, EXP2, and EXP3 are arithmetic expressions.  If any expression is
    omitted, it behaves as if it evaluates to 1.


5
#! /bin/bash

function do_something {
   echo value=${1}
}

MAX=4
for (( i=0; i<MAX; i++ )) ; {
   do_something ${i}
}

Ecco un esempio che può funzionare anche in shell più vecchie, pur essendo efficiente per grandi numeri:

Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'

Ma buona fortuna nel fare cose utili all'interno di awk: Come si usano le variabili di shell in uno script awk?


2
Non l'avevo notato prima, ma una sintassi simile è mostrata in una delle risposte precedenti. La cosa unica qui è l'uso delle parentesi graffe al posto della tipica coppia do/ done.
Brent Bradburn

4

Di solito mi piace usare una leggera variante del ciclo for standard. Lo uso spesso per eseguire un comando su una serie di host remoti. Approfitto dell'espansione delle parentesi graffe di bash per creare cicli for che mi consentono di creare cicli for non numerici.

Esempio:

Voglio eseguire il comando uptime sugli host frontend 1-5 e backend host 1-3:

% for host in {frontend{1..5},backend{1..3}}.mycompany.com
    do ssh $host "echo -n $host; uptime"
  done

Di solito lo eseguo come un comando a riga singola con punto e virgola alle estremità delle righe invece della versione più leggibile sopra. La considerazione chiave sull'utilizzo è che le parentesi graffe consentono di specificare più valori da inserire in una stringa (ad es. Pre {foo, bar} post risultati in prefoopost, prebarpost) e consentono il conteggio / sequenze utilizzando i doppi punti (è possibile utilizzare a. .z ecc.). Tuttavia, la sintassi del doppio periodo è una nuova funzionalità di bash 3.0; le versioni precedenti non lo supporteranno.


In relazione a questo, cosa succede se $ host var è una riga vuota per errore? Avrebbe comunque attivato ssh. Quindi, come lo evito? Nel mio caso sto facendo qualcosa di diverso e quindi la tua risposta mi aiuterà. Sto cercando di controllare la presenza di nuovi messaggi in Gmail e, se trovato, inviare un SMS di da e oggetto. La mia domanda è etichettata "Collegamento di due comandi Bash" se vuoi leggerlo.
Volomike

Non credo che otterresti un $ host var vuoto. Questo perché l'esempio sopra utilizza l'espansione delle parentesi graffe. Il ciclo for imposta esplicitamente la variabile $ host sui valori: frontend1.mycompany.com frontend2.mycompany.com. . backend1.mycompany.com Ma se vedi un modo per avere un valore nullo; Sarei interessato a saperlo. Potresti eseguire ssh all'interno di un test condizionale se fosse un problema.
terson

1

se sei interessato solo a bash la soluzione "for ((...))" presentata sopra è la migliore, ma se vuoi qualcosa di conforme a POSIX SH che funzioni su tutti gli Unix dovrai usare "expr" e "while", e questo perché "(())" o "seq" o "i = i + 1" non sono così portabili tra le varie shell


0

Uso sempre variazioni di questo per elaborare i file ...

per i file in * .log; do echo "Fai cose con: $ files"; echo "Fai più cose con: $ files"; fatto;

Se l'elaborazione di elenchi di file è ciò che ti interessa, controlla l' opzione -execdir per i file .


Penso che intendi l'opzione -execdir per trovare
In pausa fino a nuovo avviso.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.