2012-03-15 4 views
50

Başhkta tupller üzerinde döngü yapmak mümkün mü?Başhta tuplelara mı geçtin?

for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done 

nasılsa dizilerini üzerinde bana döngü sağlayan bir çözüm var mı: çalışmış aşağıdaki eğer bir örnek olarak

, harika olurdu? (man builtins itibaren)

set bu kullanımı hakkında
+2

piton kökenli geliyor bu gerçekten çok yararlı bir sorudur! –

+3

Bu dört yıl boyunca baktığımda hala bunu yapmanın daha iyi bir yolu olup olmadığını merak ediyorum. Aman Tanrım. – Giszmo

cevap

58
$ for i in c,3 e,5; do IFS=","; set -- $i; echo $1 and $2; done 
c and 3 
e and 5 

: konumsal parametreler için değerleri ve $ 1, $ 2, sırayla, atanır olarak

seçenek işlemlerinden kalan Herhangi argümanlar davranılır, ... $ n

IFS="," yüzden her $ibölünür alır alan ayırıcısını setlerive $2 doğru şekilde.

this blog üzerinden.

Düzenleme: daha doğru versiyonu @SLACEDIAMOND önerdiği gibi:

$ OLDIFS=$IFS; IFS=','; for i in c,3 e,5; do set -- $i; echo $1 and $2; done; IFS=$OLDIFS 
c and 3 
e and 5 
+7

Nice - sadece komut satırında çalıştırılırsa, IFS'nin kaydedilip orijinal değerine sıfırlanması gerektiğini belirtmek istersiniz. Ayrıca, yeni "IFS", döngüden önce her yineleme yerine bir kez ayarlanabilir. – Devourant

+1

@SLACEDIAMOND: teşekkürler, önerilerinizi ekledim. –

+0

$ i'den herhangi biri bir tire ile başlıyorsa, 'set' - $ i ' –

0

Biraz daha karmaşık ama yararlı olabilir:

a='((c,3), (e,5))' 
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "$1" ] && echo i=$1 j=$2; }; done 
4
$ echo 'c,3;e,5;' | while IFS=',' read -d';' i j; do echo "$i and $j"; done 
c and 3 
e and 5 
6
c=('a' 'c') 
n=(3 4) 

for i in $(seq 0 $((${#c[*]}-1))) 
do 
    echo ${c[i]} ${n[i]} 
done 

bazen daha Olabilir kullanışlı. açıklamalarda belirtildiği gibi

, ugly parçası açıklamak için:

seq 0 2 olarak 0 1 2 $ (Cmd) dizisini üreten, komut ikamesi olan seq 0 2 Bu, örneğin çıkış yüzden sayı dizisidir. Ama üst sınır nedir, $((${#c[*]}-1))?

$ ((somthing)) aritmetik genişletme, yani $ ((3 + 4)) 7 vb. Bizim İfademiz ${#c[*]}-1, yani bir şey - 1. ${#c[*]}'un ne olduğunu biliyorsak oldukça basit.

c bir dizidir, c [*] sadece tüm dizidir, $ {# c [*]}, bizim durumumuzdaki 2 dizinin boyutudur. Şimdi herşeyi geri alıyoruz:for i in $(seq 0 $((2-1)))for i in $(seq 0 1)for i in 0 1 olduğunu. Dizideki son öğe, Dizinin uzunluğu olan bir dizine sahip olduğu için - 1.

+1

$ için i 'ini yapmalısınız (seq 0 $ (($ # c [*]} - 1))); yapmak [...] ' – reox

+0

@ reox: Bitti. Teşekkürler. –

+1

Vay, bu “Gördüğüm En Keyifli Karakterler Bunch” ödülünü kazandı. Bu iğrençliğin tam olarak ne yaptığını açıklayan var mı? Hash işaretinde kayboldum ... – koniiiik

10

Bu çözüm, görüntülenen diğerlerinden biraz daha temiz olduğuna inanıyorum, gösterimi için this bash stil kılavuzu Okuma, dizeleri bir sınırlayıcıda bölmek ve bunları bireysel değişkenlere atamak için nasıl kullanılabilir.

for i in c,3 e,5; do 
    IFS=',' read item1 item2 <<< "${i}" 
    echo "${item1}" and "${item2}" 
done 
1

kullanarak GNU Paralel:

parallel echo {1} and {2} ::: c e :::+ 3 5 

veya:

parallel -N2 echo {1} and {2} ::: c 3 e 5 

ya da (ayrıca sözlük/hashmap olarak da bilinir)

parallel --colsep , echo {1} and {2} ::: c,3 e,5 
+1

Bunun için aşk yok mu? iyi yapılmış * ben * atalet üstesinden gelmek ve 'gnu parallel' – javadba

+1

' yüklemek – javadba

0

, birleştirici dizisi:

declare -A pairs=(
    [c]=3 
    [e]=5 
) 
for key in "${!pairs[@]}"; do 
    value="${pairs[$key]}" 
    echo "key is $key and value is $value" 
done 

Bash4.0 + için çalışır.


Eğer belki bir gün ihtiyacı en yerine çiftlerinin üç katına düşünüyorsanız, daha genel bir yaklaşım kullanabilirsiniz:

animals=(dog cat mouse) 
declare -A sound=(
    [dog]=barks 
    [cat]=purrs 
    [mouse]=cheeps 
) 
declare -A size=(
    [dog]=big 
    [cat]=medium 
    [mouse]=small 
) 
for animal in "${animals[@]}"; do 
    echo "$animal ${sound[$animal]} and it is ${size[$animal]}" 
done 
İlgili konular