2013-06-19 15 views
10

Jak używać zmiennej w pętli bash? Gdybym po prostu użyć standard dla pętli, to robi to, czego oczekujęJak używać zmiennych w bash dla pętli

for i in {0..3} 
do 
    echo "do some stuff $i" 
done 

To działa prawidłowo. Zapętla się 4 razy, od 0 do 3 włącznie, drukując wiadomość i licząc na końcu.

do some stuff 0 
do some stuff 1 
do some stuff 2 
do some stuff 3 

Gdy próbuję samo z następujących pętli, wydaje się równać ciąg, który nie jest to, co chcę.

length=3 
for i in {0..$length} 
do 
    echo "do something right $i" 
done 

wyjściowa:

do something right {0..3} 

Próbowałem

for i in {0.."$length"} and for i in {0..${length}} (both output was {0..3}) 

i

for i in {0..'$length'} (output was {0..$length}) 

i oboje nie robić to, co muszę. Mam nadzieję, że ktoś może mi pomóc. Z góry dziękujemy za pomoc eksperta od bash dla pętli.

Odpowiedz

12

Jednym ze sposobów jest użycie eval:

for i in $(eval echo {0..$length}) 
do 
     echo "do something right $i" 
done 

Uwaga co się dzieje, gdy ustawiona length=;ls lub length=; rm * (nie próbujcie tego ostatniego chociaż).

bezpiecznie korzystając seq:

for i in $(seq 0 $length) 
do 
     echo "do something right $i" 
done 

lub można użyć stylu C do pętli, która jest również bezpieczne:

for ((i = 0; i <= $length; i++)) 
do 
     echo "do something right $i" 
done 
+3

+1 Nie jestem fanem 'eval' ale podoba mi się sposób w jaki dajesz różne opcje w tej odpowiedzi. –

+1

Pętla w stylu C jest oczywiście najlepszą opcją. –

4

w bash, rozwijanie nawiasów jest pierwszy próbowano wykonać krok, w tym momencie $length nie zostanie zastąpiony.

manpage dla stanów bash wyraźnie:

Sekwencja ekspresja ma postać {x..y [.. przyrostowo]}, gdzie x i y oznaczają liczby całkowite lub albo pojedyncze znaki ...

Istnieje wiele możliwości, takie jak zastosowanie:

pax> for i in $(seq 0 $length) ; do echo $i ; done 
0 
1 
2 
3 

mimo że może dać dużą linię poleceń jeśli length jest masywny.

Inną alternatywą jest skorzystanie z C-like składni:

pax> for ((i = 0; i <= $length; i++)) ; do echo $i; done 
0 
1 
2 
3 
3

Brace subtitutions są wykonywane przed każdy inny, więc trzeba użyć eval lub trzeciego strona narzędzie jak seq.

Przykład eval:

for i in `eval echo {0..$length}`; do echo $i; done 

Ta informacja może być w rzeczywistości znajdują się w man bash:

Sekwencja ekspresja ma postać {x..y [.. przyrostowo]}, gdzie x i y są liczbami całkowitymi lub pojedynczymi znakami, a incr, opcjonalny przyrost, jest liczbą całkowitą. [...]

nawiasów wykonywana jest przed innymi rozszerzeniami, a wszelkie znaki specjalne do innych rozszerzeń są zachowywane w wyniku. Jest to ściśle tekstowe. Bash nie stosuje żadnej interpretacji składniowej do kontekstu rozszerzenia ani tekstu między nawiasy klamrowe.

Powiązane problemy