Dereference birleştirilmiş değişken adı


12

Bunu yapabilirim, ancak değişkenin bir dizesini oluşturup daha sonra kayıttan çıkarmayı gerektirir. Daha basit bir ifadeyle kısaltmanın bir yolu var mı?

#!/bin/bash

FRUITS="BANANA APPLE ORANGE"

BANANA_COLOUR="Yellow"
APPLE_COLOUR="Green or Red"
ORANGE_COLOUR="Blue"

for fruit in $( echo $FRUITS ); do
    fruit_colour="${fruit}_COLOUR"
    echo $fruit is ${!fruit_colour}
done

Ben gibi birçok şey denedim ${!"${fruit}_COLOUR"}ya \$${fruit}_COLOURdiğer birçok varyantları ve fakat çalıştı tek yolu bir dize kullanmaktır.


!Sözdizimi temelde “iki kez yerine” diyor değişken değişimi üzerine bir bayraktır. İçindekilerin ${…}değişken bir isim olması gerekliliğini değiştirmez . Bu nedenle, farklı bir yöntem ( eval) kullanmazsanız, adı içeren bir değişken kullanmaktan kaçınamazsınız .
Gilles 'SO- kötü olmayı bırak'

Bunu daha temiz yapmak için ilişkilendirilebilir diziler de kullanabilirsiniz. Ancak, sorunuza doğrudan bir cevap değil, bu yüzden sadece bir yorum olarak ekleyin.
Patrick

Yanıtlar:


11

Öncelikle $(echo $FRUITS), forifadede kullanmanıza gerek yok . Sadece kullanmak $FRUITSyeterlidir. Sonra kullanarak, döngü içindeki çizgilerden birini ortadan kaldırabilirsiniz eval.

evalBasitçe ikinci olmak için Bash söyler değerlendirmeyi aşağıdaki ifadenin (yani bir tane daha normal değerlendirilmesi yerine). \$İlk değerlendirmeyi hayatta $ve sonraki değerlendirme o zaman bu davranır $"Sarı" vb hangi giderir bir değişken adı başlangıcı olarak

Bu şekilde, geçici bir dize oluşturan ayrı bir adımınız olması gerekmez (bu, sorunuzun ana amacı olduğuna inanıyorum).

for fruit in $FRUITS ;do
    eval echo $fruit is \$${fruit}_COLOUR
done

Bir yorumda (yukarıda) Patrick tarafından belirtildiği gibi alternatif bir yöntem için, bunun yerine bir öğenin dizininin bir tamsayı olması gerekmeyen ilişkilendirilebilir bir dizi kullanabilirsiniz . Bir meyve türünün adı gibi bir dize kullanabilirsiniz. İşte bash ilişkisel dizisini kullanan bir örnek:

# This declares an associative array (It unsets it if it already exists)
declare -A colour
colour['BANANA']="Yellow"
colour["APPLE"]="Green or Red"
colour[MARTIAN ORANGE]="Blue"

for fruit in BANANA APPLE "MARTIAN ORANGE" ;do 
    echo "$fruit" is "${colour[$fruit]}"
done

6

Bunu evalyapmak için bash yerleşimini kullanabilirsiniz:

#!/bin/bash
FRUITS="BANANA APPLE ORANGE"
BANANA_COLOUR="Yellow"
APPLE_COLOUR="Green or Red"
ORANGE_COLOUR="Blue"

for fruit in $( echo $FRUITS );
do
    fruit_colour=${fruit}_COLOUR
    eval echo $fruit is \$${fruit_colour}
done

Ters eğik dolar işareti not edin. Temel olarak, "eval" hattı bash ikame edilmesine neden olur $fruitve ${fruit_color}daha sonra evalçağırmadan önce ikinci bir yuvarlama turu yapmak için kullanılır echo.


1

Değerlendirme ifadesine ihtiyacınız yok. evalçoğu dilde yanlış bir şey yaptığınıza dair bir ipucudur.

foo_var=10
bar_var=12

# Build a string with your var name of choice
chosen_prefix='foo'
var_name="${chosen_prefix}_var"

# Use bang to deference it
chossen_value=${!var_name}
echo "Chossen value: ${chossen_value}"

Kullanmanın daha güvenli olduğunu iddia ediyorum evalçünkü en azından insanlar tehlikeli olduğunu biliyorlar ${!var}, bash(aynı zamanda $chosen_prefixbir saldırganın kontrolü altındaysa bir komut enjeksiyon güvenlik açığı ) ve daha az insan bunun farkında. Deneyin var_name='a[$(uname>&2)0]' bash -c 'v=${!var_name}'. Buradaki en iyi yaklaşım ilişkisel dizidir.
Stéphane Chazelas
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.