Dalam bash, apakah mungkin untuk menggunakan variabel integer dalam kontrol loop dari for for?

65

Saya memiliki skrip bash berikut:

#!/bin/bash

upperlim=10

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

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

forLoop pertama ( tanpa variabel upperlimdalam kontrol loop) berfungsi dengan baik, tetapi forloop kedua ( dengan variabel upperlimdalam kontrol loop) tidak. Apakah ada cara saya bisa memodifikasi forloop kedua sehingga berfungsi? Terima kasih atas waktunya.

Andrew
sumber
4
hm, bahkan for i in {0..$((upperlim))}; do echo $i; donetidak berfungsi
Bonsi Scott
dan +1 karena menurut saya perilaku itu menarik
Bonsi Scott
kemungkinan duplikat lintas situs: stackoverflow.com/questions/169511/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Tautan eksternal yang menjawab ini: cyberciti.biz/faq/…
kon psych

Jawaban:

62

Alasan untuk ini adalah urutan di mana hal-hal terjadi di bash. Ekspansi brace terjadi sebelum variabel diperluas. Untuk mencapai tujuan Anda, Anda perlu menggunakan C-style untuk loop:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done
jordanm
sumber
1
Dan berfungsi zshjuga (tetapi tidak untuk csh, tcsh).
matematika
29

Untuk menyelesaikan ini dalam gaya Anda menggunakan apa-apa selain built-in Anda harus menggunakan eval:

d=12

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

Tetapi dengan seq:

lowerlimit=0
upperlimit=12

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

Secara pribadi saya menemukan penggunaan seqmenjadi lebih mudah dibaca.

Jodie C
sumber
Untuk "bawaan"? seqadalah perintah eksternal dan tidak tersedia di mana-mana bash.
jordanm
9
@jordanm: Untuk menggunakan semua bawaan dengan bash. Lalu saya berkata "tetapi dengan seq", mengakui bahwa itu bukan bawaan.
Jodie C
Fakta bahwa ekspansi brace dibangun bukanlah masalah di sini. readadalah builtin misalnya, tetapi tidak ada alasan untuk evalitu.
jordanm
1
Builtin tidak bermasalah sama sekali. Saya ingin memberikan solusi all-bash untuk penanya. Jika Anda ingin terus berdebat tentang ini, bawa ke obrolan; komentar tidak baik untuk hal semacam ini
Jodie C
8

Cara POSIX

Jika Anda peduli tentang portabilitas, gunakan contoh dari standar POSIX :

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

Keluaran:

2
3
4
5

Hal-hal yang bukan POSIX:

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber
1

Pendekatan Anda tidak akan berfungsi karena ekspansi bash brace terjadi sebelum ekspansi parameter. Anda perlu memperluas variabel sebelum.

Anda dapat bekerja dengan eval :

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

Dengan Loop Sementara :

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

Anda juga dapat melakukannya dengan perintah seq :

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

Jika Anda ingin menjalankannya, for i in {0..$upperlim}Anda harus menggunakan kornshell. misalnya:

#!/bin/ksh
upperlim=10

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