Kabuk betiği “for” döngüsü sözdizimi


191

Çalışmak için aşağıdakileri aldım:

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

Bu satır bir demet üreten output: 2, output: 3vb.

Ancak, aşağıdakileri çalıştırmayı deneyin:

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

aşağıdakileri üretir:

output: {2..10}

Derleyiciyi $ max dizesinin bir parçası olarak değil, dizenin bir parçası olarak ele alması gerektiğini nasıl anlayabilirim?


2
hangi sistemi ve kabuğu kullanıyorsunuz? Ne tür bir aptal sistem sh veya bash vardır, ama seq, coreutil yoktur?
whatsisname

11
FreeBSD bunu yapmaz.
Nietzche-jou

echo "$iolsa echo "$i"- sorunu çözmeyecek.
Dave Jarvis

Küçük stil nit: Genellikle dove thenanahtar kelimelerini sırasıyla forve ile aynı satırda görürüm if. Örneğin,for i in {2..10}; do
ücretli bir inek

Yanıtlar:


234

Brace genişletmesi, {x..y} diğer genişletmelerden önce gerçekleştirilir, dolayısıyla bunu değişken uzunluklu diziler için kullanamazsınız.

Bunun yerine, kullanmak seq 2 $maxgibi bir yöntemi kullanıcı mob belirtti .

Yani, örneğin için:

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

seqFor döngüsünde sayıları saymak ve artırmak gibi harici bir komut kullanmak için iyi bir neden yoktur , bu nedenle kullanmaktan kaçınmanız önerilir seq. Bu komut eski bash ile uyumluluk için bırakılmıştır. Yerleşik komutlar yeterince hızlıdır. for (( EXP1; EXP2; EXP3 )) ...
miller

13
miller for (( ... ))sözdizimi POSIX değildir ve bu, örneğin Alpine Linux gibi şeylerde kutudan çıkmayacağı anlamına gelir. seqyapar.
Wernight

@Wernight Sadece Alpine Linux değil; #!/bin/shDebian / Ubuntu'da Dash.
Franklin Yu

72

Şunun aritmetik ifade sürümünü deneyin for:

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

Bu, bash'ın birçok sürümünde mevcuttur ve Bourne kabuğu (sh) ile de uyumlu olmalıdır.


1
@Flow: Hm, #! / Bin / sh ile birkaç sistemde (Linux ve BSD tabanlı) denedim ve iyi çalıştı. Bash altında ve özellikle / bin / sh altında çağrıldı, hala çalıştı. Belki sh sürümü önemlidir? Eski bir Unix'te misin?
sistem DURAKLAT

8
Çok az sistem adanmıştır sh, bunun yerine onu başka bir kabuğa bağlar. İdeal olarak, böyle bir kabuk sadece POSIX standardındaki bu özellikleri destekleyecek, ancak varsayılan olarak bazı ekstra özelliklerinin geçmesine izin shverecektir . C stili for-loop bir POSIX özelliği değildir, ancak gerçek kabuk tarafından modda olabilir . sh
chepner

27

Döngüyü elle adımlayın:

I = 0
max = 10
[$ i -lt $ max]
yapmak
    echo "çıktı: $ i"
    gerçek $ ((i ++))
tamam

Eğer tamamen POSIX olmak zorunda yoksa, sen aritmetik kullanabilirsiniz için döngü:

max = 10
için ((i = 0; i <maks; i ++)); echo yapmak "output: $ i"; tamam

Veya kullanım zerre BSD sistemlerinde (1):

$ i için (not 0 10); echo yapmak "output: $ i"; tamam

3
true $(( i++ ))her durumda çalışmaz, bu yüzden çoğu taşınabilir olurdu true $((i=i+1)).
Akış

noktalı virgül "((i = 0; i <max; i ++));"
logan

9

Bunu yapmanın birden fazla yolu var.

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

7
Güvenlik riski, ayarladığınız her şeyieval değerlendireceğinden . Düşünün , sonra daha yıkıcı bir şeyle değiştirin . maxmax="2}; echo ha; #"echo ha
chepner

6
(S) maks. 10'a ayarladı. Risk yok.
Conrad Meyer

9

seqSisteminizde mevcut komut varsa :

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

Değilse, zavallı adamın aşağıdakileri seqile kullanın perl:

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

Şu alıntı işaretlerine dikkat et.


Ben sadece kontrol ettim; öyle görünmüyor.
eykanal

5

Bu bir yol:
Bash:

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

Yukarıdaki Bash yolu için çalışacak kshve zshçok zaman bash -cdeğiştirilir ksh -cveya zsh -csırasıyla.

Not: ve for i in {2..${max}}; do echo $i; doneiçinde çalışır .zshksh


4

Döngüyü C programlama gibi tekrarlayabiliriz.

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

2

Burada Mac OS X üzerinde çalıştı.

BSD tarihi örneğini, tarihi nasıl artıracağınızı ve azaltacağınızı içerir:

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

2

seqSistemimde (Mac OS X v10.6.1 (Snow Leopard)) yüklü komut olmadığından, whilebunun yerine bir döngü kullandım:

max=5
i=1

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

* Omuz silkiyor * Her ne olursa olsun.


2
seq nispeten yenidir. Bunu sadece birkaç ay önce öğrendim. Ama yapabilirsiniz loop 'için' bir kullanın !! Bir "while" ın dezavantajı, sayacı döngü içinde bir yerde artırmayı veya aşağıya doğru döngü yapmayı hatırlamanız gerektiğidir.
sistem DURAKLAT

1

Bunların hepsi POSIX'tir {1..8}ve olmalıdır. Döngüde bir koşullu koyarsanız da kırılmazlar continue. Standart yöntem:

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

Diğer yol:

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

ve başka:

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

1

kullanın:

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

Değişken değiştirmeden sonra {} değerini yeniden değerlendirmek için açık 'eval' çağrısına ihtiyacınız var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.