Beşlerle saymak için bir senaryoyu nasıl yapabilirim?


10

375 ve 3500 (375, 380, 385 ...) arasındaki beşin katlarını listelemek için çok basit bir bash betiği yapmaya çalışıyordum. Denediğim ve çalışmadığım bir şey:

for i in {375..3500}
do
        echo $i
        (($i += 5))
done

Bir süre sonra vazgeçtim ve BASIC'te yaklaşık 15 saniye içinde yazdım:

10 count = 375
20 print count
30 count = count+5
40 if count < 3500 then goto 20

BASIC programımı bash dilinde nasıl yapabilirim?


yığın taşması için bu daha iyi - Unix & Linux kodlama değil işletim sistemi ile ilgili. Kodlama yığın akışı içindir.
noɥʇʎԀʎzɐɹƆ

Yanıtlar:


20

Alternatif olarak, döngü için geleneksel bir C stili kullanılabilir:

for ((i=375; i<=3500; i+=5)); do
    echo $i
done

Bu, seq kullanmaktan daha az açıktır, ancak herhangi bir alt işlem oluşturmaz. C'ye aşina olduğumdan, bunu anlamakta zorlanmam, YMMV.


1
Bu yöntemin dezavantajı, daha az taşınabilir olmasıdır. Seq yöntemi POSIX sh.
Wouter Verhelst

Oh, POSIX sh'de döngüler için C stili yok mu? Her gün yeni bir şeyler öğreniyorsun ...
Muzer

2
@WouterVerhelst POSIX sh ile sınırlı değilseniz, GNU coreutils'in bir parçası olan seq'e sahip olmayacaksınız. busybox daha sınırlı bir uygulamaya sahiptir, ancak bunun dışında birçok gömülü sistem muhtemelen hiç kullanmayacaktır.
Chris Down

1
@Muzer - en azından dashdesteklemiyor. @ChrisDown - "POSIX sh" in "no seq" anlamına gelmesinin bir nedeni yoktur. Ama evet, kabul ettim ki, seq'in POSIX tarafından belirtilmediği gerçeğini göz ardı etmiştim.
Wouter Verhelst

27

Brace genişletmeyi yine de kullandığınız için, bu özellikten tam olarak yararlanın:

echo {375..3500..5}

Bu tekniği ayrıca , örneğin printfyerine aşağıdakileri kullanarak her sayıyı isteğe bağlı metinle ayrı bir satıra yazdırmak için de kullanabilirsiniz echo:

$ printf "Number %s is generated.\n" {375..3500..5}
Number 375 is generated.
Number 380 is generated.
Number 385 is generated.
...

Düzenle

@ Kojiro'nun yorumda belirttiği gibi, Mac OS varsayılan kabuk olarak bash 3'ü kullanır, bu da küme ayracı genişlemesinin sıralı ifadesinde artışı desteklemez. Bash sürüm 4'e yükseltmeniz veya bunu destekleyen başka bir kabuk kullanmanız gerekir (örn. En son zsh).


2
Mac OS 10.10.3'te bu benim için çalışmıyor. '{375..3500..5}' çıktısı verir.
aswine

6
@aswine bu yüzden sorurken işletim sisteminizden her zaman bahsetmelisiniz. Özellikle OSX'in hem diğer UNICE'lardan hem de Linux'tan birtakım farklılıkları olduğu için.
terdon

2
Bu bir işletim sistemi farkı değildir. Bu bir sürüm farkı. OS X yalnızca BASH 3 OOTB'ye sahiptir. Neredeyse tüm OS X paket yöneticilerini kullanarak bu yüzyıldan itibaren bir BASH kurabilirsiniz. Biri için Home Brew kullanıyorum.
kojiro

2
Genişlemelerin doğrudan başarısız olması, ancak bash -ciki farklı merminin yer almasını hemen hemen garanti eder. Mu $SHELL --version's bash 3 söylemek?
dhag

3
@mikeserv Cevap çok basit - bunu yazmadım çünkü bashbu özelliğin hangi versiyonunun tanıtıldığına dair hiçbir fikrim yoktu . Kendimi kojiro yorumundan öğrendim. Ve lütfen SC ile karşılaştırmayın, 1970 sonlarından beri tüm mermilerin tüm detaylarını ve tarihini gerçekten bilmiyorum. Bir kez daha - Bunu bekliyorsanız, lütfen aşağı inin.
jimmij

17

SEQ Kullanımı (1)

for i in $(seq 375 5 3500)
do
    echo $i
done

Ya da sadece:

seq 375 5 3500

4
Daha da basit olan, döngüyü düşürmek ve kullanmaktır seq 375 5 3500.
dhag

11

Döngü snippet'iniz iki nedenden dolayı istediğiniz gibi çalışmadı:

  • (($i += 5))- Burada $ideğeri değerine genişletilir i. Böylece genişleme ((375 += 5))mantıklı olmayan bir şey olacaktır (başka bir değişmez sayıya değişmez sayı atamaya çalışmak). Bu normalde ((i += 5))( $değişkeni genişletmek için hayır )
  • Bu {375..3500}döngü, döngünün ilk yinelemesinden önce genişletilir. Sayıların listesi olacak 375 376 ... 3499 3500. Döngünün her yinelemesi iiçin, bu numaraların her birine tek tek atanacaktır. Böylece her yinelemenin başlangıcında, ibu listedeki bir sonraki değere yeniden atanır. 1'lik adımlarla geri sayılır. ((i += 5))Etkili bir şey yapmaz - i'ye 5 ekler, ancak sonra yeniden yeniden başlatılır sonraki yineleme.

Sanırım for (( ; ; ))cevabı en çok sevdim , ama düşünmenizi sağlayacak bazı alternatifler:


5'in katları ile uğraştığımız ve {a..b..i}genişleme bas sürüm 3.2.57 (1) 'de (OS X'te) desteklenmediğinden, bunun yerine bu biraz gizli şeyi yapabiliriz:

for i in 375 {38..349}{0,5} 3500; do
    echo $i
done

Bu, bash'ın kartezyen bir ürün oluşturmak için nasıl kullanılabileceğini gösterir.


Genel olarak bir for döngüsü, bunu yapmanın en uygun yolu olduğunu düşünüyorum, ancak ilgileniyorsanız, bir while-loop (BASIC'inize biraz daha yakın) programı kullanabilirsiniz:

count=375
while (( count <= 3500 )); do
    echo $count
    (( count += 5 ))
done

1
@jimmij ... Kartezyen ürün nedir? İsterseniz yorumu aşağıya aktarabilirsiniz ve bana söyleseniz bile umrumda değil. Merak ediyorum.
mikeserv

1
@mikeserv yorumu aşağıya indiremezsiniz: en.wikipedia.org/wiki/Cartesian_product
jimmij

@jimmij - eğer yaparsan benimle hala sorun yok.
mikeserv

@jimmij Şeytandan bahsediyor musun? Kartezyen bir ürün, iki setten (aynı set olabilir veya olmayabilir) her olası eleman kombinasyonunun bir kümesidir. Daha genel olarak, iki şey grubundan sadece "tüm olası kombinasyonlar" dır. Sadece bir set görüyorum. Burada Kartezyen bir ürün nasıl var?
jpmc26

1
İlk yazma üzerindeki tüm numaraları den - @ jpmc26 Haklısınız, o kadar olaylar iki eksen olanak tanıyor "tüm olası kombinasyonları" dır 38kadar 349. İkinci olarak sadece iki sayı: 0ve 5. Şimdi bu tüm kombinasyonların sipariş çiftleri oluşturmanızı sağlar - Bir set olarak yazabiliriz: {38,0}, {38,5}... {349,5}, ya da sadece gereksiz simgeleri kaldırın {, ,ve }ve almak ... yeni numaralar 380... 3495.
jimmij

5

Elbette, bunun için bir uygulama ( seq 375 5 3500) olsa da, bunu komut satırından yapmanın çeşitli yolları vardır. En hızlı ve en basit olanı sadece kullanırken seq, diğer bazı seçenekler şunlardır:

for i in {375..3500}; do [[ (($i % 5)) -eq 0 ]] && echo $i; done

i=370; while [ $i -le 3500 ]; do printf "%s\n" $((i+=5)); done

perl -le '$i=shift;while($i<=$ARGV[0]){print $i; $i+=5; }' 375 3500
perl -le 'map{print $_ + 5} 370..3495'

awk 'BEGIN{ for(i=375;i<=3500;i+=5){print i}}'

Nit pick: $(($i % 5))yazılabilir $((i % 5)).
G-Man,

4

POSIXly:

i=370
while [ 3500 -gt "$i" ]
do    echo "$((i+=5))"
done

...veya...

echo 'for(x=370;x<=3500;x+=5)x' |bc

Neden başka bir yolla yapacağınızı bilmiyorum. Tabii ki hariç ...

seq 375 5 3500

... veya dc:

echo '370[5+pd3500>p]splpx'|dc

dcKodun nasıl çalıştığını merak ediyorum . Kesinlikle kullanmaktan daha ilgi çekicidir seq.
dhag

1
@dhag - küçük bir döngü yazar. Bu saves [dize ]üstüne p, daha sonra bir dizi lyığını ve e üst kısmına geri OAD'ler xbir makro olarak ecutes o. 5Yığının üzerine bastığımız makro içinde, sonra onu ve ikincisini üstten ve +onlardan, her iki yığın değerini de daha önce pçizilen ve dkopyalanan toplamlarıyla değiştirmek, yığına bastığımızda ve az önce 3500yaptığımız dupe karşılaştırma >. Eğer 3500büyüktür, biz yük ve makro olarak yürütmek saklanan dize pdizisi (mevcut makro) veya kırılmaz eğer.
mikeserv

3

Bash 3'te takılı kalırsanız:

echo {375..3500} | tr ' ' '\n' | sed -n 'p;n;n;n;n'

ve isterseniz awk:

echo {375..3500} | tr ' ' '\n' | awk '!((NR-1)%5)'

Brace genişlemesi hakkında bilmiyordum - bu gerçekten harika.

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.