Bash'deki değişkenler tarafından tanımlanan bir dizi sayıyı nasıl yineleyebilirim?


1543

Aralık bir değişken tarafından verildiğinde Bash'deki bir sayı aralığını nasıl yineleyebilirim?

Bunu yapabilirim (Bash belgelerinde "dizi ifadesi" denir ):

 for i in {1..5}; do echo $i; done

Hangi verir:

1
2
3
4
5

Yine de, aralık uç noktalarından herhangi birini bir değişkenle nasıl değiştirebilirim? Bu işe yaramaz:

END=5
for i in {1..$END}; do echo $i; done

Hangi baskılar:

{1..5}


26
Merhabalar, burada okuduğum bilgiler ve ipuçları gerçekten çok faydalı. Ben seq kullanmaktan kaçınmak en iyisidir düşünüyorum. Bunun nedeni, bazı komut dosyalarının taşınabilir olması ve bazı komutların bulunmayabileceği çok çeşitli unix sistemlerinde çalışması gerektiğidir. Sadece bir örnek vermek gerekirse, seq FreeBSD sistemlerinde varsayılan olarak mevcut değildir.


9
Bash'in tam olarak hangi versiyonundan beri hatırlamıyorum ama bu komut da sıfırları destekliyor. Hangi bazen gerçekten yararlı. Komut for i in {01..10}; do echo $i; donegibi sayılar verirdi 01, 02, 03, ..., 10.
topr

1
Benim gibi sadece bir dizinin indeks aralığı üzerinde yineleme yapmak isteyenler için , bash yolu şöyle olurdu: myarray=('a' 'b' 'c'); for i in ${!myarray[@]}; do echo $i; done(ünlem işaretini not edin). Orijinal sorudan daha spesifik, ancak yardımcı olabilir. Bkz. Bash parametre genişletmeleri
PlasmaBinturong

1
Brace genişletmesi, {jpg,png,gif}doğrudan burada ele alınmayan gibi ifadeler için de kullanılır , ancak yanıt aynı olacaktır. Bkz. Değişken ile küme ayracı genişletmesi? [duplicate], bunun kopyası olarak işaretlenir.
Üçlü

Yanıtlar:


1744
for i in $(seq 1 $END); do echo $i; done

edit: seqAslında hatırlayabiliyorum çünkü diğer yöntemleri tercih ederim ;)


36
seq, genellikle işleri yavaşlatan harici bir komutun yürütülmesini içerir. Bu önemli olmayabilir, ancak çok fazla veriyi işlemek için bir komut dosyası yazıyorsanız önemli hale gelir.
paxdiablo

37
Sadece bir astar için iyi. Pax'ın çözümü de iyi, ancak performans gerçekten bir endişe olsaydı bir kabuk betiği kullanmazdım.
eschercycle

17
seq sayıları üretmek için sadece bir kez çağrılır. exec () 'bu döngü başka bir sıkı döngü içinde olmadıkça anlamlı olmamalıdır.
Javier

29
Harici komut gerçekten uygun değildir: harici komutların çalıştırılması yükü hakkında endişeleniyorsanız, kabuk komut dosyalarını kullanmak istemezsiniz, ancak genellikle unix'te ek yük düşüktür. Ancak END yüksekse bellek kullanımı sorunu vardır.
Mark Baker

18
Not seq $ENDVarsayılan itibaren 1'den başlamak gibi, yeterli olacaktır man seq"ilk ve artış atlanırsa, bu 1 dir".
fedorqui 'SO

473

seqYöntem en basit olmakla birlikte, Bash yerleşik aritmetik değerlendirme.

END=5
for ((i=1;i<=END;i++)); do
    echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines

for ((expr1;expr2;expr3));Yapı gibi çalışır for (expr1;expr2;expr3)araçlar ve benzeri dillerde ve diğer benzeri ((expr))durumlarda, Bash aritmetik olarak davranır.


67
Bu şekilde büyük bir listenin bellek yükünü ve bağımlılığı önler seq. Kullanın!
bobbogo

3
@MarinSagovac Bu yaptığı iş ve hiçbir sözdizimi hataları vardır. Kabuğunun Bash olduğundan emin misin?
gniourf_gniourf

3
@MarinSagovac #!/bin/bashKomut dosyanızın ilk satırını yaptığınızdan emin olun . wiki.ubuntu.com/...
Melebius

7
bunun hakkında çok kısa bir soru: neden ((i = 1; i <= END; i ++)) AND NOT ((i = 1; i <= $ END; i ++)); neden END önce $ yok?
Baedsch

5
@Baedsch: aynı nedenden dolayı i $ i olarak kullanılmaz. arhmetik değerlendirme için bash man sayfası durumları: "Bir ifade içinde, kabuk değişkenlerine parametre genişletme sözdizimi kullanılmadan adla da başvurulabilir."
user3188140

193

tartışma

Kullanılması seqJiaaro önerildiği gibi, gayet iyi. Pax Diablo, $ END çok büyükse daha fazla bellek dostu olmanın ek avantajı ile bir alt işlem çağırmamak için bir Bash döngüsü önerdi. Zathrus, döngü uygulamasında tipik bir hatayı fark etti ve ayrıca ibir metin değişkeni olduğu için, sürekli-ileri-geri sayı dönüşümlerinin ilişkili bir yavaşlama ile gerçekleştirildiğini ima etti .

tam sayı aritmetiği

Bu, Bash döngüsünün geliştirilmiş bir sürümüdür:

typeset -i i END
let END=5 i=1
while ((i<=END)); do
    echo $i
    
    let i++
done

İstediğimiz tek şey ise echo, o zaman yazabiliriz echo $((i++)).

ephemient bana bir şey öğretti: Bash for ((expr;expr;expr))yapılara izin veriyor . Bash için tüm adam sayfasını hiç okumadığımdan beri (Korn shell ( ksh) adam sayfasıyla yaptığım gibi ve bu uzun zaman önceydi), bunu özledim.

Yani,

typeset -i i END # Let's be explicit
for ((i=1;i<=END;++i)); do echo $i; done

en verimli bellek yolu gibi görünüyor (tüketmek için bellek ayırmaya gerek yok seqmuhtemelen "en hızlı" çok büyükse sorun olabilir), çıkışını .

ilk soru

eschercycle { a .. b } Bash gösteriminin sadece değişmez değerlerle çalıştığını belirtti; Bash kılavuzuna göre doğrudur. Bir tek (dahili) ile bu engeli aşabiliriz fork()bir olmadan exec()(çağırarak örneğinde olduğu gibi seqbaşka bir görüntü olan bir çatal + exec gerektiren,):

for i in $(eval echo "{1..$END}"); do

Her ikisi de evalve echoBash yerleşikleridir, ancak fork()komut ikamesi ( $(…)yapı) için a gereklidir .


1
C stili döngüsünün "$" ile başlayan komut satırı argümanlarını kullanamamasının tek dezavantajı.
karatedog

3
@karatedog: for ((i=$1;i<=$2;++i)); do echo $i; donebir komut dosyasında bash v.4.1.9'da benim için iyi çalışıyor, bu yüzden komut satırı argümanlarında bir sorun görmüyorum. Başka bir şey mi demek istiyorsun?
12'de tzot

Eval çözümünün C-benzeri yerleşik için daha hızlı olduğu görülüyor: $ time for ((i = 1; i <= 100000; ++ i)); yapmak :; gerçek 0m21.220s kullanıcı 0m19.763s sys 0m1.203s $ i için zaman ($ eval echo "{1..100000}"); yapmak :; yapılan; gerçek 0m13.881s kullanıcı 0m13.536s sys 0m0.152s
Marcin Zaluski

3
Evet, ama eval kötülük ... @MarcinZaluski time for i in $(seq 100000); do :; doneçok daha hızlı!
F. Hauri

Değerlendirme sürümü makinemde en hızlı olduğu için performans platforma özel olmalıdır.
Andrew Prock

103

Orijinal ifadenin çalışmadığı neden budur.

Gönderen adam bash :

Köşeli ayraç genişletmesi diğer genişletmelerden önce gerçekleştirilir ve sonuçta diğer genişletmelere özel karakterler korunur. Kesinlikle metinseldir. Bash, genişleme bağlamına veya parantezler arasındaki metne sözdizimsel bir yorum uygulamaz.

Bu nedenle, küme ayracı genişletmesi , parametre genişletmeden önce tamamen metinsel bir makro işlemi olarak yapılan bir şeydir .

Kabuklar, makro işlemciler ve daha resmi programlama dilleri arasında oldukça optimize edilmiş hibritlerdir. Tipik kullanım durumlarını optimize etmek için dil oldukça daha karmaşık hale getirilir ve bazı sınırlamalar kabul edilir.

Öneri

Posix 1 özelliklerine bağlı kalmanızı öneririm . Bu for i in <list>; do, eğer liste zaten biliniyorsa, aksi halde, whileveya kullanmak için kullanılır seq:

#!/bin/sh

limit=4

i=1; while [ $i -le $limit ]; do
  echo $i
  i=$(($i + 1))
done
# Or -----------------------
for i in $(seq 1 $limit); do
  echo $i
done


1. Bash harika bir kabuk ve etkileşimli olarak kullanıyorum, ama senaryomlara bash-isms koymuyorum. Komut dosyalarının daha hızlı bir kabuk, daha güvenli bir kabuk, daha gömülü tarzda bir kabuk olması gerekebilir. / Bin / sh olarak yüklenen her şeyde çalıştırılması gerekebilir ve daha sonra tüm standart standartlar argümanları vardır. Kabuğu hatırlıyor musun , aka bashdoor?


13
Gücüm yok, ama bunu her şeyden önce listenin biraz üstüne taşıyordum.
mateor

2
Bunun bir anlamı, küme ayracı genişlemesinin seqgeniş aralıklarla karşılaştırıldığında çok fazla bellek tasarrufu yapmamasıdır . Örneğin, echo {1..1000000} | wcyankının 1 satır, bir milyon kelime ve 6.888.896 bayt ürettiğini ortaya çıkarır. Çalışılıyor seq 1 1000000 | wcile ölçülen verimleri bir milyon satır, bir milyon kelime ve 6.888.896 bayt ve fazla yedi kat daha hızlı da timekomuta.
George

Not: POSIX whileyönteminden daha önce
cevabımda bahsetmiştim

Bu yanıtı aşağıdaki performans karşılaştırma yanıtıma ekledim. stackoverflow.com/a/54770805/117471 (Bu, hangisini yapmam gerektiğini takip etmek için kendime bir not.)
Bruno Bronosky

@mateor Ben döngü ve aritmetik değerlendirme için C-tarzı aynı çözüm olduğunu düşündüm. Bir şey mi kaçırıyorum?
Oscar Zhang

72

POSIX yolu

Taşınabilirliği önemsiyorsanız , POSIX standardındaki örneği kullanın :

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

Çıktı:

2
3
4
5

POSIX olmayan şeyler :

  • (( ))POSIX'in belirttiği gibi yaygın bir uzantı olmasına rağmen, dolar olmadan .
  • [[. [burada yeter. Ayrıca bakınız: Bash'te tek ve çift köşeli parantezler arasındaki fark nedir?
  • for ((;;))
  • seq (GNU Coreutils)
  • {start..end}ve Bash kılavuzunda belirtildiği gibi değişkenlerle çalışamaz .
  • let i=i+1: POSIX 7 2. Kabuk Komut Dili sözcüğü içermiyor letve bash --posix4.3.42'de başarısız oluyor
  • adresindeki dolar i=$i+1gerekli olabilir, ancak emin değilim. POSIX 7 2.6.4 Aritmetik Genişleme şöyle diyor:

    Kabuk değişkeni x, isteğe bağlı olarak önde gelen artı veya eksi işareti içeren geçerli bir tamsayı sabiti oluşturan bir değer içeriyorsa, "$ ((x))" ve "$ (($ x))" aritmetik genişletmeleri aynı döndürür değer.

    ancak kelimenin tam anlamıyla okumak , bir değişken olmadığı için $((x+1))genişlediği anlamına gelmez x+1.


Bu cevapta son derece olağandışı 4 upvotes vardı. Bu, bazı bağlantı toplama web sitesinde yayınlandıysa, lütfen bana bir bağlantı verin, şerefe.
Ciro Santilli 法轮功 19: 46 事件 法轮功

Alıntı xtüm ifadeyi değil, anlamına gelir . $((x + 1))sadece iyi.
chepner

Taşınabilir olmasa da ve GNU'dan farklı olsa da seq(BSD seq, bir dizi sonlandırma dizesi ayarlamanızı sağlar -t), FreeBSD ve NetBSD'nin seqsırasıyla 9.0 ve 3.0'dan beri var .
Adrian Günter

@CiroSantilli @chepner $((x+1))ve $((x + 1))ayrıştırma tamamen aynı, ayrıştırıcı sıfırlar olduğu gibi x+1bu 3 jeton içine bölünmüş olacaktır: x, +, ve 1. xgeçerli bir sayısal belirteç değildir, ancak geçerli bir değişken adı belirtecidir, ancak x+bölünmez. +geçerli bir aritmetik işleç belirtecidir, ancak +1değildir, bu nedenle belirteç yine oraya bölünür. Ve böylece.
Adrian Günter

Bu yanıtı aşağıdaki performans karşılaştırma yanıtıma ekledim. stackoverflow.com/a/54770805/117471 (Bu, hangisini yapmam gerektiğini takip etmek için kendime bir not.)
Bruno Bronosky

35

Başka bir dolaylama katmanı:

for i in $(eval echo {1..$END}); do
    

2
+1: Ayrıca, {1 .. '$ END'} içindeki 'i için değerlendirme yapın; do ... 'eval bu sorunu çözmek için doğal bir yol gibi görünüyor.
William Pursell

28

Kullanabilirsiniz

for i in $(seq $END); do echo $i; done

seq, genellikle işleri yavaşlatan harici bir komutun yürütülmesini içerir.
paxdiablo

9
Her bir yineleme için sadece bir kez harici bir komutun yürütülmesini içermez. Bir harici komutun başlatılma süresi önemliyse, yanlış dili kullanıyorsunuz demektir.
Mark Baker

1
Peki, bunun önemli olduğu tek durum yuvalamak mı? Bir performans farkı ya da bilinmeyen bir teknik yan etki olup olmadığını merak ediyordum?
Sqeaky

@Squeaky Bu, burada cevaplanan ayrı bir soru: stackoverflow.com/questions/4708549/…
tripleee

Bu yanıtı aşağıdaki performans karşılaştırma yanıtıma ekledim. stackoverflow.com/a/54770805/117471 (Bu, hangisini yapmam gerektiğini takip etmek için kendime bir not.)
Bruno Bronosky

21

Bunun gibi olabileceğinden daha fazla önek gerekiyorsa

 for ((i=7;i<=12;i++)); do echo `printf "%2.0d\n" $i |sed "s/ /0/"`;done

bu getirecek

07
08
09
10
11
12

4
Bundan printf "%02d\n" $idaha kolay olmaz mıydı printf "%2.0d\n" $i |sed "s/ /0/"?
zb226

19

BSD / OS X kullanıyorsanız seq yerine jot kullanabilirsiniz:

for i in $(jot $END); do echo $i; done

17

Bu iyi çalışıyor bash:

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

6
echo $((i++))çalışır ve tek bir satırda birleştirir.
Bruno Bronosky

1
Bunun gereksiz bash uzantıları var. POSIX sürümü: stackoverflow.com/a/31365662/895245
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

1
@Ciro, soru özellikle bash'ı belirttiğinden ve bir bash etiketine sahip olduğundan, muhtemelen bash 'uzantılarının'
tamamdan

@paxdiablo Doğru değil demek istemiyorum ama neden olabildiğince taşınabilir olmasın ;-)
Ciro Santilli 法轮功 病毒 审查 六四 事件 法轮功

İçinde bash, sadece while [[ i++ -le "$END" ]]; dotestte (post-) artışı yapabiliriz
Aaron McDaid

14

Burada birkaç fikri birleştirdim ve performansı ölçtüm.

TL; DR Paket İçeriği:

  1. seqve {..}gerçekten hızlı
  2. forve whiledöngüler yavaş
  3. $( ) yavaş
  4. for (( ; ; )) döngüler daha yavaş
  5. $(( )) daha yavaş
  6. Endişesi N saçma ({..} seq veya) hafızasına sayı olduğu (1 milyon, en azından kadar).

Bunlar bir sonuç değildir . Sonuç çıkarmak için bunların her birinin arkasındaki C koduna bakmanız gerekir. Bu daha çok, bu mekanizmaların her birini kod üzerinde döngü için nasıl kullandığımızla ilgilidir. Çoğu tek işlem, çoğu durumda önemli olmayacak kadar hızlı olacak kadar yakındır. Ama benzer bir mekanizma for (( i=1; i<=1000000; i++ ))görsel olarak görebileceğiniz gibi birçok işlemdir. Ayrıca döngü başına aldığınızdan çok daha fazla işlemdir for i in $(seq 1 1000000). Ve bu sizin için açık olmayabilir, bu yüzden böyle testler yapmak değerlidir.

Demos

# show that seq is fast
$ time (seq 1 1000000 | wc)
 1000000 1000000 6888894

real    0m0.227s
user    0m0.239s
sys     0m0.008s

# show that {..} is fast
$ time (echo {1..1000000} | wc)
       1 1000000 6888896

real    0m1.778s
user    0m1.735s
sys     0m0.072s

# Show that for loops (even with a : noop) are slow
$ time (for i in {1..1000000} ; do :; done | wc)
       0       0       0

real    0m3.642s
user    0m3.582s
sys 0m0.057s

# show that echo is slow
$ time (for i in {1..1000000} ; do echo $i; done | wc)
 1000000 1000000 6888896

real    0m7.480s
user    0m6.803s
sys     0m2.580s

$ time (for i in $(seq 1 1000000) ; do echo $i; done | wc)
 1000000 1000000 6888894

real    0m7.029s
user    0m6.335s
sys     0m2.666s

# show that C-style for loops are slower
$ time (for (( i=1; i<=1000000; i++ )) ; do echo $i; done | wc)
 1000000 1000000 6888896

real    0m12.391s
user    0m11.069s
sys     0m3.437s

# show that arithmetic expansion is even slower
$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $i; i=$(($i+1)); done | wc)
 1000000 1000000 6888896

real    0m19.696s
user    0m18.017s
sys     0m3.806s

$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $i; ((i=i+1)); done | wc)
 1000000 1000000 6888896

real    0m18.629s
user    0m16.843s
sys     0m3.936s

$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $((i++)); done | wc)
 1000000 1000000 6888896

real    0m17.012s
user    0m15.319s
sys     0m3.906s

# even a noop is slow
$ time (i=1; e=1000000; while [ $((i++)) -le $e ]; do :; done | wc)
       0       0       0

real    0m12.679s
user    0m11.658s
sys 0m1.004s

1
Güzel! Yine de özetinize katılmayın. Bana öyle geliyor $(seq)ki aynı hızda {a..b}. Ayrıca, her işlem yaklaşık aynı zaman alır, bu yüzden benim için her döngü yinelemesine yaklaşık 4μs ekler. Burada bir işlem vücuttaki bir yankı , aritmetik bir karşılaştırma, bir artış, vs.'dir. Bunlardan herhangi biri şaşırtıcı mı? Döngü gereçlerinin işini yapmasının ne kadar sürdüğünü kimin umurunda - çalışma zamanının döngü içeriği tarafından baskın olması muhtemeldir.
bobbogo

@bobbogo haklısın, gerçekten operasyon sayısı hakkında. Cevabımı bunu yansıtacak şekilde güncelledim. Yaptığımız birçok çağrı aslında beklediğimizden daha fazla işlem gerçekleştiriyor. Bunu çalıştırdığım yaklaşık 50 test listesinden daralttım. Araştırmamın bu kalabalık için bile çok gergin olmasını bekliyordum. Her zaman olduğu gibi, kodlama çabalarınıza şu şekilde öncelik vermenizi öneririm: Kısaltın; Okunabilir yapın; Daha cabuk yap; Taşınabilir yapın. Genellikle # 1, # 3'e neden olur. Zorunda olana kadar 4. vaktinizi boşa harcamayın.
Bruno Bronosky

8

Bu sorunun hakkında olduğunu biliyorum bash, ama - sadece kayıt için - ksh93daha akıllı ve beklendiği gibi uygular:

$ ksh -c 'i=5; for x in {1..$i}; do echo "$x"; done'
1
2
3
4
5
$ ksh -c 'echo $KSH_VERSION'
Version JM 93u+ 2012-02-29

$ bash -c 'i=5; for x in {1..$i}; do echo "$x"; done'
{1..5}

8

Bu başka bir yol:

end=5
for i in $(bash -c "echo {1..${end}}"); do echo $i; done

1
Bu, başka bir mermi yumurtlama yüküne sahiptir.
codeforester

1
Aslında, bu çok korkunç çünkü 1 yeterli olduğunda 2 mermi ortaya çıkarıyor.
Bruno Bronosky

8

Brace-ifade sözdizimine mümkün olduğunca yakın kalmak istiyorsanız, rangeişlevi bash-tricks 'denrange.bash deneyin .

Örneğin, aşağıdakilerin tümü tam olarak aynı şeyi yapar echo {1..10}:

source range.bash
one=1
ten=10

range {$one..$ten}
range $one $ten
range {1..$ten}
range {1..10}

Yerel bash sözdizimini olabildiğince az "gotchas" ile desteklemeye çalışır: yalnızca değişkenler desteklenmez, aynı zamanda geçersiz aralıkların dizeler (örneğin for i in {1..a}; do echo $i; done) olarak sağlanması gibi istenmeyen davranışları da önlenir.

Diğer cevaplar çoğu durumda işe yarar, ancak hepsinin aşağıdaki dezavantajlarından en az biri vardır:

  • Birçoğu kullanmak altkabuklarda olabilir, performansına zarar ve mümkün olmayabilir bazı sistemlerde.
  • Birçoğu harici programlara güveniyor. seqKullanılması için yüklenmesi gereken, bash tarafından yüklenmesi gereken ve bu durumda çalışması için beklediğiniz programı içermesi gereken bir ikili dosya bile . Her yerde ya da her yerde, sadece Bash dilinin kendisinden daha fazla güvenmek gerekiyor.
  • @ Ephemient'inki gibi yalnızca yerel Bash işlevlerini kullanan çözümler, örneğin alfabetik aralıklarda çalışmaz {a..z}; küme ayracı genişletme. Soru, sayı aralıklarıyla ilgiliydi , bu yüzden bu bir tartışma .
  • Çoğu, {1..10}küme ayracı genişletilmiş aralık sözdizimine görsel olarak benzemez, bu nedenle her ikisini de kullanan programların okunması biraz daha zor olabilir.
  • @ bobbogo'nun cevabı tanıdık sözdiziminin bir kısmını kullanır, ancak $ENDdeğişken aralığın diğer tarafı için geçerli bir "bookend" aralığı değilse beklenmedik bir şey yapar . Eğer END=a, örneğin, bir hata oluşmaz ve harfi harfine değeri {1..a}yankılandı edilecektir. Bu, Bash'ın varsayılan davranışıdır - genellikle beklenmediktir.

Feragatname: Bağlantılı kodun yazarıyım.



6

Bunların hepsi güzel ama seq sözde itiraz edildi ve çoğu sadece sayısal aralıklarla çalışıyor.

For döngünüzü çift tırnak içine alırsanız, dizeyi yankıladığınızda başlangıç ​​ve bitiş değişkenlerinin kaydı kaldırılır ve dizeyi yürütmek üzere doğrudan BASH'e gönderebilirsiniz. $i\ 'ın kaçması gerekir, bu nedenle alt kabuğa gönderilmeden önce DEĞİLDİR.

RANGE_START=a
RANGE_END=z
echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash

Bu çıktı bir değişkene de atanabilir:

VAR=`echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash`

Bunun üretmesi gereken tek "ek yük", bash'ın ikinci örneği olmalıdır, bu nedenle yoğun operasyonlar için uygun olmalıdır.


5

Kabuk komutları yapıyorsanız ve (benim gibi) boru hattı için bir fetişiniz varsa, bu iyi:

seq 1 $END | xargs -I {} echo {}


3

Bunu yapmanın birçok yolu vardır, ancak tercih ettiğimler aşağıda verilmiştir.

kullanma seq

Özeti man seq

$ seq [-w] [-f format] [-s string] [-t string] [first [incr]] last

Sözdizimi

Tam komut
seq first incr last

  • birincisi sıradaki başlangıç ​​numarasıdır [varsayılan olarak isteğe bağlıdır: 1]
  • incr artıştır [varsayılan olarak isteğe bağlıdır: 1]
  • son sıradaki son sayıdır

Misal:

$ seq 1 2 10
1 3 5 7 9

Sadece ilk ve son ile:

$ seq 1 5
1 2 3 4 5

Sadece sonuncusu ile:

$ seq 5
1 2 3 4 5

kullanma {first..last..incr}

Burada ilk ve son zorunludur ve incr isteğe bağlıdır

Sadece ilk ve son kullanma

$ echo {1..5}
1 2 3 4 5

İncr kullanma

$ echo {1..10..2}
1 3 5 7 9

Bunu aşağıdaki gibi karakterler için bile kullanabilirsiniz

$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z

3

eğer kullanmak istemiyorsanseq ' veya ' eval' veya jotveya aritmetik genişleme biçimini örn. for ((i=1;i<=END;i++))veya diğer döngüler örn. whileve yalnızca ' printf' ve ' ' mutlu olmak istemezseniz echo, bu basit geçici çözüm bütçenize uygun olabilir:

a=1; b=5; d='for i in {'$a'..'$b'}; do echo -n "$i"; done;' echo "$d" | bash

PS: Bash'ımın seqzaten ' ' komutu yok .

Mac OSX 10.6.8, Bash 3.2.48 üzerinde test edildi


0

Bu Bash ve Korn'da çalışır, aynı zamanda daha yüksekten daha düşük sayılara da gidebilir. Muhtemelen en hızlı veya en güzel değil ama yeterince iyi çalışıyor. Negatifleri de ele alır.

function num_range {
   # Return a range of whole numbers from beginning value to ending value.
   # >>> num_range start end
   # start: Whole number to start with.
   # end: Whole number to end with.
   typeset s e v
   s=${1}
   e=${2}
   if (( ${e} >= ${s} )); then
      v=${s}
      while (( ${v} <= ${e} )); do
         echo ${v}
         ((v=v+1))
      done
   elif (( ${e} < ${s} )); then
      v=${s}
      while (( ${v} >= ${e} )); do
         echo ${v}
         ((v=v-1))
      done
   fi
}

function test_num_range {
   num_range 1 3 | egrep "1|2|3" | assert_lc 3
   num_range 1 3 | head -1 | assert_eq 1
   num_range -1 1 | head -1 | assert_eq "-1"
   num_range 3 1 | egrep "1|2|3" | assert_lc 3
   num_range 3 1 | head -1 | assert_eq 3
   num_range 1 -1 | tail -1 | assert_eq "-1"
}
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.