Czy w bash można zastosować zmienną całkowitą do sterowania pętlą for?

65

Mam następujący skrypt bash:

#!/bin/bash

upperlim=10

for i in {0..10}
do
echo $i
done

for i in {0..$upperlim}
do
echo $i
done

Pierwsza forpętla ( bez zmiennej upperlimw kontrolce pętli) działa dobrze, ale druga forpętla ( ze zmienną upperlimw kontrolce pętli) nie działa. Czy jest jakiś sposób na zmodyfikowanie drugiej forpętli, aby działała? Dziękuję za Twój czas.

Andrzej
źródło
4
hm, nawet for i in {0..$((upperlim))}; do echo $i; donenie działa
Bonsi Scott
i +1, ponieważ uważam to zachowanie za interesujące
Bonsi Scott
możliwy duplikat witryny: stackoverflow.com/questions/169511/...
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Zewnętrzny link, który odpowiada na to: cyberciti.biz/faq/...
kon

Odpowiedzi:

62

Powodem tego jest kolejność, w której rzeczy występują w bash. Rozwinięcie nawiasów następuje przed rozwinięciem zmiennych. Aby osiągnąć swój cel, musisz użyć stylu C dla pętli:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done
Jordan
źródło
1
I pracuje zshjak dobrze (ale nie za csh, tcsh).
matematyka
29

Aby wykonać to w swoim stylu za pomocą wbudowanych funkcji, musisz użyć eval:

d=12

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

Ale z seq:

lowerlimit=0
upperlimit=12

for i in $(seq $lowerlimit $upperlimit)
do
echo $i
done

Osobiście uważam, że użycie seqjest bardziej czytelne.

Jodie C.
źródło
Dla „wbudowanych”? seqjest zewnętrznym poleceniem i nie jest dostępne wszędzie, gdzie jest bash.
Jordan
9
@jordanm: Do używania wszystkich wbudowanych poleceń z bash. Potem powiedziałem „ale z seq”, uznając, że to nie jest wbudowane.
Jodie C,
Fakt, że wbudowana jest ekspansja nawiasów, nie jest tutaj problemem. readjest na przykład wbudowany, ale nie ma żadnego powodu eval.
Jordan
1
Wbudowane nie są w ogóle problematyczne. Chciałem zapewnić pytającemu kompleksowe rozwiązanie. Jeśli chcesz się o to kłócić, weź to na czacie; komentarze nie są dobre dla tego rodzaju rzeczy
Jodie C
8

Sposób POSIX

Jeśli zależy Ci na przenośności, skorzystaj z przykładu standardu POSIX :

i=2
END=5
while [ $i -le $END ]; do
    echo $i
    i=$(($i+1))
done

Wynik:

2
3
4
5

Rzeczy, które nie są POSIX:

Ciro Santilli
źródło
1

Twoje podejście nie będzie działać, ponieważ w bash interpretacja nawiasów występuje przed rozszerzaniem parametrów. Musisz wcześniej rozwinąć zmienną.

Możesz obejść z eval :

upperlim=10
eval '
        for i in {0..'"$upperlim"'}
        do
                echo $i
        done
'

Z pętlą While :

upperlim=10
#with while
start=0
while [[ $start -le $upperlim ]]
do
    echo "$start"
    ((start = start + 1))
done

Możesz to również zrobić za pomocą polecenia seq :

upperlim=10
#seq
for i in $(seq "$upperlim"); do
  echo "$i"
done

Jeśli chcesz biegać for i in {0..$upperlim}, musisz użyć kornshell. na przykład:

#!/bin/ksh
upperlim=10

for i in {0..$upperlim}
do
        echo $i
done
Kheshav Sewnundun
źródło