Sintaks skrip shell "for" loop


191

Saya mendapatkan yang berikut ini untuk bekerja:

for i in {2..10}
do
    echo "output: $i"
done

Ini menghasilkan sekelompok baris output: 2, output: 3, seterusnya.

Namun, coba jalankan hal berikut:

max=10
for i in {2..$max}
do
    echo "$i"
done

menghasilkan yang berikut:

output: {2..10}

Bagaimana saya bisa membuat kompiler menyadari bahwa ia harus memperlakukan $ max sebagai ujung array, dan bukan bagian dari string?


2
sistem dan shell apa yang Anda gunakan? Sistem konyol macam apa yang memiliki sh atau bash, tetapi tidak memiliki seq, sebuah coreutil?
whatsisname

11
FreeBSD tidak.
Nietzche-jou

echo "$iseharusnya echo "$i"- tidak akan memperbaiki masalah, meskipun.
Dave Jarvis

Gaya nit kecil: Saya biasanya melihat dodan thenkata kunci pada baris yang sama dengan fordan if, masing-masing. Misalnya,for i in {2..10}; do
kutu buku yang dibayar

Jawaban:


234

Perluasan brace, {x..y} dilakukan sebelum ekspansi lainnya, jadi Anda tidak bisa menggunakannya untuk urutan panjang variabel.

Sebaliknya, gunakan seq 2 $maxmetode sebagai pengguna mob dinyatakan .

Jadi, sebagai contoh Anda akan:

max=10
for i in `seq 2 $max`
do
    echo "$i"
done

Tidak ada alasan yang baik untuk menggunakan perintah eksternal seperti sequntuk menghitung dan menambah angka dalam for loop, karena itu disarankan agar Anda tidak menggunakan seq. Perintah ini dibiarkan untuk kompatibilitas dengan bash lama. Perintah bawaan cukup cepat. for (( EXP1; EXP2; EXP3 )) ...
pabrik

13
@miller for (( ... ))sintaksnya bukan POSIX dan itu artinya misalnya tidak akan bekerja di luar kotak pada hal-hal seperti Alpine Linux. seqtidak.
Wernight

@ Wight Tidak Hanya Alpine Linux; #!/bin/shadalah Dash di Debian / Ubuntu.
Franklin Yu

72

Coba versi ekspresi aritmatika for:

max=10
for (( i=2; i <= $max; ++i ))
do
    echo "$i"
done

Ini tersedia di sebagian besar versi bash, dan harus kompatibel dengan Bourne shell (sh).


1
@Flow: Hm, saya baru mencobanya di beberapa sistem (berbasis Linux dan BSD) dengan #! / Bin / sh dan itu bekerja dengan baik. Dipanggil di bawah bash dan secara khusus di bawah / bin / sh, masih berfungsi. Mungkin versi sh penting? Apakah Anda menggunakan Unix lama?
system PAUSE

8
Sangat sedikit sistem yang memiliki dedicated sh, alih-alih menjadikannya tautan ke shell lain. Idealnya, shell seperti itu dipanggil karena hanyash akan mendukung fitur-fitur tersebut dalam standar POSIX, tetapi secara default membiarkan beberapa fitur tambahan melaluinya. C-style for-loop bukan fitur POSIX, tetapi mungkin dalam mode oleh shell yang sebenarnya. sh
chepner

27

Langkah loop secara manual:

i = 0
maks = 10
sementara [$ i -lt $ max]
melakukan
    echo "output: $ i"
    true $ ((i ++))
selesai

Jika Anda tidak harus benar-benar POSIX, Anda dapat menggunakan aritmatika untuk loop:

maks = 10
untuk ((i = 0; i <maks; i ++)); lakukan echo "output: $ i"; selesai

Atau gunakan jot (1) pada sistem BSD:

untuk saya dalam $ (jot 0 10); lakukan echo "output: $ i"; selesai

3
true $(( i++ ))tidak berfungsi dalam semua kasus, jadi sebagian besar portabel mungkin true $((i=i+1)).
Aliran

titik koma tidak boleh berupa "for ((i = 0; i <max; i ++));"
logan

9

Ada lebih dari satu cara untuk melakukannya.

max=10
for i in `eval "echo {2..$max}"`
do
    echo "$i"
done

7
Risiko keamanan, karena evalakan mengevaluasi apa pun yang Anda tetapkan max. Pertimbangkan max="2}; echo ha; #", lalu ganti echo hadengan sesuatu yang lebih destruktif.
chepner

6
(S) ia menetapkan maksimal 10. Tidak ada risiko.
Conrad Meyer

9

Jika seqperintah tersedia di sistem Anda:

for i in `seq 2 $max`
do
  echo "output: $i"
done

Jika tidak, maka gunakan pria miskin seqdengan perl:

seq=`perl -e "\$,=' ';print 2..$max"`
for i in $seq
do
  echo "output: $i"
done

Lihat tanda kutip itu.


Saya baru saja memeriksanya; sepertinya tidak.
eykanal

5

Ini caranya:
Bash:

max=10
for i in $(bash -c "echo {2..${max}}"); do echo $i; done

Cara Bash di atas akan bekerja untuk kshdan zshjuga, ketika bash -cdiganti dengan ksh -catauzsh -c masing masing.

Catatan: for i in {2..${max}}; do echo $i; doneberfungsi di zshdan ksh.


4

Kita dapat mengulangi loop seperti pemrograman C.

#!/bin/bash
for ((i=1; i<=20; i=i+1))
do 
      echo $i
done

2

Ini berfungsi pada Mac OS X.

Ini termasuk contoh tanggal BSD, cara menambah dan mengurangi tanggal juga:

for ((i=28; i>=6 ; i--));
do
    dat=`date -v-${i}d -j "+%Y%m%d"` 
    echo $dat
done

2

Yah, karena saya tidak seqmenginstal perintah pada sistem saya (Mac OS X v10.6.1 (Snow Leopard)), saya whilemalah menggunakan loop:

max=5
i=1

while [ $max -gt $i ]
do
    (stuff)
done

* Mengangkat bahu * Apapun yang berhasil.


2
seq relatif baru. Saya baru tahu beberapa bulan yang lalu. Tapi Anda bisa menggunakan loop 'untuk' !! Kerugian dari 'sementara' adalah Anda harus ingat untuk menambah penghitung di suatu tempat di dalam loop, atau loop ke bawah.
system PAUSE

1

Semua ini dilakukan {1..8}dan semuanya POSIX. Mereka juga tidak akan rusak jika Anda menempatkan kondisional continuedalam loop. Cara kanonik:

f=
while [ $((f+=1)) -le 8 ]
do
  echo $f
done

Cara lain:

g=
while
  g=${g}1
  [ ${#g} -le 8 ]
do
  echo ${#g}
done

dan lainnya:

set --
while
  set $* .
  [ ${#} -le 8 ]
do
  echo ${#}
done

1

Menggunakan:

max=10
for i in `eval echo {2..$max}`
do
    echo $i
done

Anda memerlukan panggilan 'eval' eksplisit untuk mengevaluasi kembali {} setelah penggantian variabel.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.