Kabuk Betiklerinde İlişkisel Diziler


11

Bir kabuk komut dosyasında ilişkilendirilebilir diziler uygulamak için bir hile gördüm. Örneğin , anahtar = elmalar print array["apples"]gibi yazılabilir echo \$array$key.

Bununla birlikte, dizi üzerinde yineleme yapmak için anahtarların nasıl oluşturulacağından bahsedilmedi. Düşünebildiğim tek yol, anahtarları boşluklarla ayrılmış bir değişkente saklamaktı, böylece dizi üzerinde yineleme yapmak için bir for-loop kullanabilirsiniz.

Peki, anahtarları daha sonra kullanmak üzere saklamanın başka bir yolu var mı?


5
Bir kabuk komut dosyasında ilişkilendirilebilir diziler kullanmaya çalışıyorsanız, projenizin bir kabuk komut dosyası için çok karmaşık olması mümkün olabilir :)
Martin von Wittich

@MartinvonWittich neden? 3 olası DB şemalarından birinde SQL komut dosyası yürüten bir kabuk komut dosyası var. Gerekli şema, kısaltma ile dosya adına eklenmiştir. Bu kısaltma ve gerçek şema adı arasında bir eşleşmeye ihtiyacım var. Gerçek şema adlarını (kısaltmayı değil) dikkate alarak ilişkilendirilebilir bir diziden daha iyi bir yol, ortamlar arasında farklılık gösterebilir, bu nedenle bir dizi değişkeni (değerleri yalnızca bir kez ayarlanabilen) mükemmeldir
Slav

2
@Slav İlişkisel dizilere karşı değilim, sadece böyle karmaşıklığın gerekli olduğu kabuk betiklerine karşı değilim. Ama bu sadece benim kişisel tercihim; Sık sık bir kabuk komut dosyası yazmaya başladım ve sonra belirli bir karmaşıklık eşiğini aştığımı fark ettiğimde hemen Perl'de yeniden yazıyorum.
Martin von Wittich

Yanıtlar:


20

İlişkilendirilebilir dizili kabuklar

Bazı modern kabuklar ilişkilendirilebilir diziler sağlar: ksh93, bash ≥4, zsh. Ksh93 ve bash'da, eğer ailişkilendirilebilir bir dizi ise, o zaman "${!a[@]}"anahtarlarının dizisidir:

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

Zsh'de, bu sözdizimi yalnızca ksh öykünme modunda çalışır. Aksi takdirde, zsh'nin yerel sözdizimini kullanmanız gerekir:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a}aboş bir anahtarı yoksa da çalışır .

kZsh'de v, aynı anda hem gözlerde hem de alüyonda döngü yapabilirsiniz :

for k v ("${(@kv)a}") echo "$k -> $v"

İlişkilendirilebilir dizileri olmayan kabuklar

Onları olmayan kabuklarda ilişkisel diziler taklit etmek çok daha fazla iştir. İlişkilendirilebilir dizilere ihtiyacınız varsa, muhtemelen ksh93 veya Perl gibi daha büyük bir araç getirmenin zamanı gelmiştir.

Yalnızca bir POSIX kabuğunda ilişkilendirilebilir dizilere ihtiyacınız varsa, tuşlar yalnızca karakterleri içerecek şekilde kısıtlandığında 0-9A-Z_a-z(ASCII rakamları, harfler ve alt çizgi) bunları simüle etmenin bir yolu . Bu varsayım altında, anahtarlar değişken adlarının bir parçası olarak kullanılabilir. Aşağıdaki işlevler, ardışık iki alt çizgi içermemesi gereken bir adlandırma öneki olan “kök” ile tanımlanan bir dizi üzerinde çalışır.

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\$3
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(Uyarı, test edilmemiş kod. Sözdizimsel olarak geçersiz gövdeler ve anahtarlar için hata tespiti sağlanmamıştır.)


5

Mağaza ile ne demek istediğinizden emin değilim, ancak ${!array[@]}sözdizimini kullanarak anahtarları tekrarlayabilirsiniz :

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

Yani, yinelemek için:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

Burada güzel, kısa bir eğitim buldum .


Aşağıdaki yorumlarda belirtildiği gibi, ilişkisel diziler bashsürüm 4'te eklenmiştir . Konuyla ilgili bir Linux günlük makalesi için buraya bakın .


1
(bash version 4 only)Bu not edilmesi gereken önemli bir şey. Geleneksel olarak, bashdiziler yalnızca sayısaldır.
Ricky Beam

1
Örnekleriniz typesetyerine kullanmak isteyebilirsiniz declare. Bu, onları kabuk birleştirici dizileri ilk kez uygulayan bash 4 ve ksh93 arasında taşınabilir hale getirir.
jlliagre

0

İlişkilendirilebilir dizileri olmayan kabuklar

Tuşlarla sınırlandırıldığında [0-9A-Za-z_](sayılar, harfler, alt çizgi) o kadar da zor değil .

Hile, [ $ key ] dizisine depolamak yerine array_ $ key değişkenlerine depolamaktır .

Ayarlamak:

eval "array_$key='$value'"

Almak:

value=`eval echo '$'array_$key`

Not: Değerler içeremez '(tek tırnak).


-1

bu bash'da çalışıyor

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

VEYA

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

Eval afaik kullanmaya gerek yok


1
Sorunun amacını kaçırdığınıza inanıyorum.
G-Man
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.