A 3. oldal tartalma
Folytatás
Az előző oldalon megismerhettük az indexelt tömbök elágazásokban illetve függvényekben történő felhasználását, itt folytatjuk a tömbök használatát az asszociatív tömbökkel való megismerkedéssel.
Asszociatív tömbök
Az asszociatív tömbök nagyon hasonlítanak az indexelt tömbökhöz, annyi különbséggel, hogy a szám indexeken kívül még bármilyen szöveges indexet (más néven kulcsokat) is adhatunk a tömb elemeinek azonosítójaként. Használatuk nagyrészt ugyanúgy történik, mint az indexelt tömböknél leírtaknál, de vannak eltérések is. Így ebben a fejezetben rávilágítunk ezekre a különbségekre is.
Az Asszociatív tömbök használata a Bash 4.0-ás verziójában került be, így az ennél régebbi Bash verzióban még nem volt elérhető.
Deklarálás, értékadás
Az asszociatív tömbök deklarálása annyiban tér el az indexelt tömbökétől, hogy itt kötelező a deklarálás:
declare -A asszociativ_tomb
Az indexelt tömböknél a kis -a kapcsolóval lehetett (nem kötelezően) deklarálni, itt pedig a nagy -A -val kötelező. Erre ügyeljünk!
Először próbáljunk meg értéket tölteni deklaráció nélkül egy asszociatív tömbbe, hogy lássuk mi történik ha elfelejtjük a deklarációt:
proba["elem1"]="Első elem"
Nem adott hibát. Most kérdezzük le a már ismert módon:
echo ${proba["elem1"]}
És visszaadja az "Első elem" értéket. Hurrá!
De ha az alábbi módok bármelyikén kérdezzük le:
echo ${proba["elem2"]}
echo ${proba["masik_elem"]}
echo ${proba[0]}
echo $proba
Mindegyik esetben visszakapjuk az elején megadott "Első elem" értékünket. Mi is történik itt?
A válasz egyszerű. Az asszociatív tömböt deklaráció nélkül próbáltuk meg létrehozni, ekkor a Bash egy sima indexelt tömböt hozott helyette létre. És mivel a szögletes zárójelben megadott mezőnév nullának értékelődött ki, ezért az indexelt tömb 0. elemébe került a megadott érték. Majd ezután bármelyik módon is kérdeztük le az asszociatívnak gondolt tömbünket, mindegyikre visszaadta ugyanazt az eredményt, mivel mindegyik esetben 0-nak értékelődött ki az index helyén megadott érték. A változó egyszerű ( $proba ) kiolvasása pedig az indexelt tömböknél ugyanúgy a legelső, azaz a 0. elem értékét adja vissza. (Ennek megfelelően például az echo ${proba[1]} parancsra már üreset ad vissza.)
Így tehát most van egy indexelt tömbünk, amit ha megpróbálunk újra deklarálni asszociatívként:
declare -A proba
Akkor kapunk egy ilyen hibaüzenetet:
bash: declare: proba: nem lehetséges az indexelt tömb asszociatívvá alakítása
Ezért először töröljük a tömböt, majd deklaráljuk újra asszociatívként:
unset proba
declare -A proba
Ezután már létrejön a tömbünk.
Most már adhatunk is hozzá értékeket többféleképpen is:
proba[elem1]="Első elem"
proba["elem2"]="Második elem"
proba[kecske]=káposzta
Ezután egy egysoros ciklussal ki is olvashatjuk pont úgy, mint az indexelt tömböknél:
for i in "${!proba[@]}"; do echo "$i: ${proba[$i]}" ; done
kecske: káposzta elem3: Harmadik elem elem2: Második elem elem1: Első elem
Ha pedig rögtön a deklarálással egybekötve szeretnénk feltölteni értékekkel, és mindezt áttekinthető formában, akkor tehetjük így is például egy Shell scriptben:
1 2 3 4 5 6 7 8 #!/bin/bash declare -A proba=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" [kecske]="káposzta" )
Ellentétben a sima indexelt tömbökkel, ahol külön értéknek veszi ilyenkor a külön szót, itt a zárójelben felváltva várja az indexeket és az értékeket. Így ha egy több szavas érték nem kerül idézőjelbe, akkor úgy veszi, hogy kimaradt egy index, ezért hibát ad.
Ezért a hibák elkerülése végett célszerű hozzászokni az idézőjelek használatához bármilyen értéktípus megadásánál.
Többszavas kulcsok használata
Ha már szöveges indexeket/kulcsokat adhatunk meg, akkor felmerül az igény arra is, hogy többszavas kulcsokat is megadhassunk. Lássuk hogyan történik ez:
1 2 3 4 5 6 7 #!/bin/bash declare -A tomb=( [több szavas kulcs 1]="Idézőjel nélkül adtuk meg a kulcsot" ["több szavas kulcs 2"]="Itt pedig idézőjellel" ) declare -A
A végén a declare -A parancs pedig megmutatja nekünk hogyan néz ki a tömb a memóriában:
declare -A tomb=(["több szavas kulcs 1"]="Idézőjel nélkül adtuk meg a kulcsot" ["több szavas kulcs 2"]="Itt pedig idézőjellel" )
Itt láthatjuk, hogy mindkét értékadás sikeres volt, akár idézőjelekkel, akár azok nélkül adtuk meg a kulcsokat, a rendszer kipótolta őket, ahol nem kerültek megadásra. A szögletes zárójelek megléte miatt itt tudja értelmezni a több szóból álló címkéket is. Mindazonáltal célszerű ilyenkor is használni az idézőjelet, ha már több szavas neveket használunk a tömb indexeiben, hogy szabványosak maradjunk.
Értékek kiolvasása
Az asszociatív tömbökből hasonlóan olvashatjuk ki az értékeket, mint az indexelt tömböknél: Végigmehetünk az indexeken ciklusokkal, vagy direktben is hivatkozhatunk egy megadott elemre. Lényegében a ciklusban is direkt hivatkozást használunk a kiolvasásra, csak ilyenkor a ciklus adja sorban a tömb kulcsokat.
A következő példaprogramban feltöltünk egy asszociatív tömböt, majd megkeressük a elemei között a megadott mintát tartalmazó értékűeket:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #!/bin/bash declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" [kecske]="káposzta" [több szavas kulcs 1]="Idézőjel nélkül adtuk meg a kulcsot" ["több szavas kulcs 2"]="Itt pedig idézőjellel" ) # Keresendő karakterlánc keres="elem" for i in "${!tomb[@]}"; do if [[ ${tomb[$i]} == *"$keres"* ]]; then echo "Találat: [$i]: ${tomb[$i]}" fi done
Tömbtulajdonságok kiolvasása
A tömbtulajdonságok is ugyanúgy működnek, mint az indexelt tömböknél:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #!/bin/bash declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" ) echo "Összes elem kiolvasása egyszerre" echo ${tomb[*]} # Egy mezőként bontja ki echo ${tomb[@]} # Külön mezőkbe bontja ki # (ugyanaz a működés, mint az indexelt tömböknél) echo echo"Aposztrófokba burkolja az elemeket." echo "Egy mezőként bontja ki:" printf "'%s' \n" "${tomb[*]}" echo "Több mezőként bontja ki:" printf "'%s' \n" "${tomb[@]}" echo echo "Tartomány kiolvasása" echo ${tomb[@]:2:2} echo echo "Összes index kiolvasása:" echo ${!tomb[@]} echo echo "Tömb elemeinek a száma:" echo ${#tomb[@]} echo echo "Megadott elem karakterhosszának a kiolvasása:" echo ${#tomb["elem1"]}
Tömbök összefűzése
Az összefűzés is ugyanúgy zajlik:
1 2 3 4 5 6 7 8 9 10 11 12 13 #!/bin/bash declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" ) tomb+=( [elem4]="negyedik elem" [elem5]="ötödik elem" ) echo ${tomb[@]}
Annyi különbséggel, hogy itt az indexelt tömböknél megismert összefűzési módszer nem működik:
tomb=("${tomb[@]}" "2000" "következő elem")
Ilyenkor a következő hibát dobja: "tomb: '${tomb[@]}': asszociatív tömbhöz való értékadásnál meg kell adni az indexet"
Tehát itt csak a fenti módszerrel lehet hozzáfűzni, azaz, ha az indexeket is megadjuk.
Tömbök használata ciklusokban
Itt annyi az eltérés, hogy az asszociatív tömböknél lehetőség van több szavas kulcsokat is létrehozni. Ezáltal ha egy ciklusban nem jól kerül kibontásra az indexek listája, akkor itt nem ad hibát, hanem üres értékkel tér vissza, mivel itt szintaktikailag ugyan helyes a címzés, de a nem létező indexen nem talál értéket. Példa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #!/bin/bash declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" ) echo "Tömb indexek ciklusban történő helyes kibontása:" for i in "${!tomb[@]}"; do echo "Index: $i, értéke: ${tomb[$i]}" done echo echo "Helytelen használat, nincs visszatérő érték:" for i in "${!tomb[*]}"; do echo "Index: $i, értéke: ${tomb[$i]}" done
Kimenete:
Tömb indexek ciklusban történő helyes kibontása: Index: elem3, értéke: Harmadik elem Index: elem2, értéke: Második elem Index: elem1, értéke: Első elem Helytelen használat, nincs visszatérő érték: Index: elem3 elem2 elem1, értéke:
Ahogy a példában is látható, pontosan ugyanazt az eltérő működést produkálják a @-al illetve a *-gal történő kibontások, mint az indexelt tömböknél, csak itt az asszociatív tömböknél ez nem okoz hibát.
Tömbök használata elágazásokban
Az asszociatív tömböket pontosan ugyanúgy lehet használni az elágazásokban, mint az indexelt tömböket.
Annyi apró különbség van, hogy itt az indexeket betehetjük idézőjelek közé is. De ha már egy feltétel kifejezésén belül a tömb indexénél idézőjelet használnánk akkor az indexet aposztrófok közé tegyük, hogy elkerüljük a beágyazott idézőjeleket:
1 2 3 4 5 6 7 8 9 10 #!/bin/bash declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" [több szavas]=10 ) # Beágyazott idézőjelek elkerüléséhez használhatunk aposztrófot a több szavas inxexeknél, de nem kötelező [ "${tomb['több szavas']}" = 10 ] && echo "igaz" || echo "hamis"
Tömbök használata függvényekben
Az indexelt tömböktől eltérően itt nem működik megfelelően a paraméterek egy tömbként kezelése a függvénekben, mivel ezzel a módszerrel csak az értékeket tudjuk "összegyűjteni" a függvény számára. Míg az indexelt tömböknél nem volt jelentősége az indexeknek, itt viszont ilyenkor elvesznek a nevekkel ellátott kulcsaink, és csak az értékek "jutnak be" a függvénybe. Lássunk egy hasonló példát egy asszociatív tömbbel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #!/bin/bash declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" [több szavas]=10 ) function fuggveny { tomb2=("$@") # Összes paraméter begyűjtése egy másik tömbbe for i in "${!tomb2[@]}"; do ertek=${tomb2[$i]} echo "$i: $ertek" done } # Függvény hívása a kibontott asszociatív tömbbel fuggveny "${tomb[@]}"
Kimenet:
0: Harmadik elem 1: Második elem 2: Első elem 3: 10
Ahogy a kimenetben is látszik, elvesztek a deklarációkor létrehozott kulcsaink.
A példaprogram egyébként jól működik, pontosan azt csinálja, amit kell: A függvény hívásakor a "${tomb[@]}" szintaxissal kibontottuk az asszociatív tömb értékeit, és ezt kapta meg a függvény. Ami utána a 10. sorban létrehozott egy új indexelt tömböt a kapott értékekkel. Tehát az asszociatív tömbünkből létrejött egy indexelt tömb másolat, aminek az értékei ugyan megmaradtak, de a kulcsok elvesztek belőle, illetve sorszámokká alakultak.
A jó hír viszont, hogy a név szerinti változó hivatkozással működik szépen a dolog.
Név szerinti paraméterátadás
A korábban az indexelt tömbnél már megismert hasonló példa itt is működik:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/bin/bash declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" [több szavas]=10 ) function fuggveny { declare -n param1=$1 # A declare parancs '-n' kapcsolója oldja meg a név szerinti hivatkozást for i in "${!param1[@]}"; do ertek=${param1[$i]} echo "$i: $ertek" done } # Függvény hívása csak a tömb változónak a nevével fuggveny tomb
A kimenete pedig:
elem3: Harmadik elem elem2: Második elem elem1: Első elem több szavas: 10
Ezzel a módszerrel tehát megmaradtak a kulcsok is és az értékek is.
Itt viszont ügyelni kell, hogy a függvényben ha módosítjuk az így létrehozott változókat, akkor az az eredeti változóra is kihat a program globális névterében. Erre egy példa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #!/bin/bash # Tömb deklarálása a globális névtérben declare -A tomb=( [elem1]="Első elem" [elem2]="Második elem" [elem3]="Harmadik elem" ) function fuggveny { declare -n param=$1 echo "Eredeti tömb tartalma a módosítás előtt:" for i in "${!param[@]}"; do ertek=${param[$i]} echo "$i: $ertek" done # A függvényen belül még hozzáfűzünk újabb elemeket a tömbhöz. param+=( [ujabb elem]="Függvényben adtuk hozzá" [ujabb elem2]="Ezt is a függvényben adtuk hozzá" ) } # Függvény hívása a név szerinti paraméterrel fuggveny tomb echo echo "Az eredeti tömb tartalma a globális névtérben a függvény lefutása után:" for i in "${!tomb[@]}"; do ertek=${tomb[$i]} echo "$i: $ertek" done
A kimenet pedig:
Eredeti tömb tartalma a módosítás előtt: elem3: Harmadik elem elem2: Második elem elem1: Első elem Az eredeti tömb tartalma a globális névtérben a függvény lefutása után: elem3: Harmadik elem elem2: Második elem elem1: Első elem ujabb elem: Függvényben adtuk hozzá ujabb elem2: Ezt is a függvényben adtuk hozzá
Látható, hogy a függvényben történt módosítás után az eredeti változó tartalma is megváltozott. Mindez azért, mert egy név szerinti hivatkozást hoztunk létre a függvényben az eredeti változóra, nem pedig új változót hoztunk létre.
A következő oldalon folytatjuk a tömbök globális névtérbe történő exportálásával...
Lapozó
- A hozzászóláshoz regisztráció és bejelentkezés szükséges
- 447 megtekintés