2012-06-24 24 views
15

Bu kodu nasıl çalıştırabilirim?Dolaylı başvuru kullanarak bir dizi üzerinde yineleme nasıl yapılır?

#!/bin/bash 
ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE) 
for FRUIT in ${!ARRAYNAME[@]} 
do 
    echo ${FRUIT} 
done 

Bu kod:

echo ${!ARRAYNAME[0]} 

Baskılar APPLE. Ben benzer bir şey yapmaya çalışıyorum ama dizi üzerinde yinelemek için "[@]" ile. peşin

sayesinde

+4

bakınız [BashFAQ/006] (http://mywiki.wooledge.org/BashFAQ/006). –

cevap

18

${!ARRAYNAME[@]} vasıta "ARRAYNAME endeksleri". bash man page'da belirtildiği gibi ARRAYNAME'dan beri bir dizi değil, bir dizi olarak 0 döndürür. Bu, eval kullanarak bir çözümdür.


#!/usr/bin/env bash 

ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE) 

eval array=\(\${${ARRAYNAME}[@]} \) 

for fruit in "${array[@]}"; do 
    echo ${fruit} 
done 

Ne başlangıçta yapmaya çalışıyorduk bir Indirect Reference oluşturmak oldu. Bunlar, bash versiyon 2'de piyasaya sürüldü ve kabukta yansıma benzeri davranışlar elde etmeye çalışırken büyük ölçüde eval ihtiyacının yerini alması gerekiyordu.

Eğer değişken adı adresinden tahminim [@] bulunur diziler ile dolaylı referanslar kullanırken yapmanız gereken şey:

#!/usr/bin/env bash 

ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE) 

array="${ARRAYNAME}[@]" 
for fruit in "${!array}"; do 
    echo $fruit 
done 

Bütün bunlar, bu Dolaylı Referansları kullanmak üzere bir şey önemsiz örnek, ancak Dennis Williamson tarafından sağlanan bağlantıda belirtildiği gibi, bunları gerçek dünyadaki betiklerde kullanmakta tereddüt etmelisiniz. Bunların hepsi, kodunuzu gereğinden daha karmaşık hale getirmeyi garanti eder. Genellikle bir İlişkisel Diziyle ihtiyacınız olan işlevselliği alabilirsiniz.

+0

Tim: Cevabın 2. kısmı yararlı değil, çünkü ARRAYNAME benim betiğimin bir giriş parametresidir. Ama ilk çözümün daha zarif bir çözüm bulmama izin verin: ARRAY = $ {! ARRAYNAME}; FRUIT için $ {ARRAY [@]} ... Teşekkürler – Neuquino

+0

@Neuquino Düzenlenmiş cevabımı görün. Yapmanız gereken tek şey giriş değişkeninizin sonunda [@] 'ile birleştirmektir. –

+2

@Neuquino ARRAYNAME, komut dosyanız için bir giriş parametresiyse, çok yanlış bir şey yapıyorsunuz demektir. Kullanıcı girişini değişken isimlerle karıştırmanın sıfır nedeni vardır. Bu durumda (dolaylı genişleme ile birlikte), keyfi kod enjeksiyonuna izin verir. Bu tekniklerin YALNIZCA geçerli nedeni, hiçbir zaman global kapsamda ve asla kullanıcı girdisi ile birleştirilmemiş fonksiyonlarda kullanım içindir. – ormaaj

0

Sadece başka bir kullanışlı kullanım çantası eklemek istedim. Ben, yani dizi elemanları boşluk içeren bu cevaplar en yaygın, gerçek kullanım senaryoları için ölçek olmaz, basit OP soru rağmen farklı bir çözüm için web'de, ancak ilgili sorunu

ARRAYNAME=(FRUITS VEG) 
FRUITS=(APPLE BANANA ORANGE) 
VEG=(CARROT CELERY CUCUMBER) 
for I in "${ARRAYNAME[@]}" 
do 
    array="${I}[@]" 
    for fruit in "${!array}"; do 
     echo $fruit 
    done 
done 
+0

'array =" $ {I} [@] "' tmp = $ arrayname [@] 'ile tamamen aynı! İyileşme yok! –

0

arıyordu veya henüz dosya isimlerine genişletilmemesi gereken joker karakterler. Eğer "[email protected]" değil [email protected] kullanma alışkanlığı almalısınız gibi

FRUITS=(APPLE BANANA ORANGE 'not broken' '*.h') 
ARRAYNAME=FRUITS 
eval ARRAY="(\"\${$ARRAYNAME[@]}\")" 

$ echo "${ARRAY[3]}" 
not broken 
$ echo "${ARRAY[4]}" 
*.h 
$ 

, her zaman dosya adı genişlemesini istiyorum ya bilmedikçe hiçbir ihtimal, dizi açılımları için () içeride alıntı:

FRUITS=(APPLE BANANA ORANGE 'not broken' '*.h') 
ARRAYNAME=FRUITS 
eval ARRAY=\(\${$ARRAYNAME[@]}\) 

$ echo "${ARRAY[4]}" 
broken 
$ echo "${ARRAY[5]}" 
config.h 
$ 

Bu işleri Boşluk içeren dizi elemanların

yapın: X=("${Y[@]}")

değil bu: X=(${Y[@]})

8

İşte eval olmadan bunu yapmak için bir yoldur.

Bash hüner 2. Burada anlatılan bakınız: http://mywiki.wooledge.org/BashFAQ/006

bash 3 ve yukarı çalışmaya görünüyor.

#!/bin/bash 

ARRAYNAME='FRUITS' 
tmp=$ARRAYNAME[@] 
FRUITS=(APPLE BANANA ORANGE "STAR FRUIT") 
for FRUIT in "${!tmp}" 
do 
    echo "${FRUIT}" 
done 

Burada bir fonksiyonu referansla bir dizi geçmesine gösteren daha gerçekçi bir örnek verilmiştir:

pretty_print_array() { 
    local arrayname=$1 
    local tmp=$arrayname[@] 
    local array=("${!tmp}") 
    local FS=', ' # Field seperator 
    local var 
    # Print each element enclosed in quotes and separated by $FS 
    printf -v var "\"%s\"$FS" "${array[@]}" 
    # Chop trailing $FS 
    var=${var%$FS} 
    echo "$arrayname=($var)" 
} 
FRUITS=(APPLE BANANA ORANGE "STAR FRUIT") 
pretty_print_array FRUITS 
# prints FRUITS=("APPLE", "BANANA", "ORANGE", "STAR FRUIT") 
+0

da böyle bir dolaylı dizinin boyutunu değerlendirmek için herhangi bir yol mu var? –

0

Eval bunlar, örneğin, komut ikameleri içeren bile kodu içeren dizi elemanlarını çalıştırır. Aynı zamanda, dizi öğelerini, onların içinde bash meta karakterlerini yorumlayarak değiştirir. Bu sorunları önler

tek araç bir referans olup:

#!/bin/bash 
declare -n ARRAYNAME='FRUITS' 
FRUITS=(APPLE BANANA ORANGE "BITTER LEMON") 
for FRUIT in "${ARRAYNAME[@]}" 
do 
    echo "${FRUIT}" 
done 
İlgili konular