Tömbök kezelése és használata a Shell scriptekben

botond küldte be 2019. 03. 11., h – 17:08 időpontban

Az 1. oldal tartalma

 

Bevezető

A programozás során gyakran szükség van a tömbök használatára, melyekkel egyszerre több értéket is tárolhatunk, amiket utána akár ciklusokban dolgozhatunk fel automatizáltan. Nincs ez másképp a Shell scriptek esetén sem. Ebben a leírásban példákon keresztül tekintjük meg, hogyan használhatjuk a tömb változókat különböző szituációkban a Shell scriptjeinkben.

 

 

Indexelt tömbök

Az indexelt tömbök a tömbök egyszerűbbik fajtája. Ennél a típusnál a tömb elemei számértékekhez, más néven indexekhez vannak társítva. Az indexeket a legtöbb programnyelvben nem kötelező megadni, ebben az esetben az adott programnyelv értelmezője vagy fordítója hozza létre őket automatikusan.

Lássunk néhány példát a használatukról a Bash shell script-jeiben.

Deklarálás, értékadás

Az indexelt tömböket nem kötelező előre deklarálni, hanem elég csak egy kezdőértéket megadni neki:

tomb[1]=200

Vagy szöveges érték esetén:

tomb[2]="több szavas érték"

Az értékek Ellenőrzését a legegyszerűbben a Bash beépített declare parancsával végezhetjük, a -a kapcsolóval:

declare -a

A parancs ekkor kiírja a shell névterében lévő összes indexelt tömböt, köztük az imént létrehozottat is:

[...]
declare -a tomb=([1]="200" [2]="több szavas érték")

Itt megfigyelhetjük, hogy ha így adunk értékeket egy tömbnek, akkor ezek a tömb más elemeire nincsenek hatással. Azaz, hogyha korábban már létezett a tömb, akkor a korábbi adatok benne maradnak, csak az újonnan beállított index értéke íródik felül. Ezért amikor először használunk egy tömböt, akkor célszerű azt a zárójeles módszerrel létrehozni, és egyből feltölteni egy vagy több kezdőértékkel:

tomb=("első érték" "második érték" 3 mégegy)

Ilyenkor a tömb korábbi tartalma törlődik és 0-tól induló indexeléssel bekerülnek az értékek a tömbbe.

declare -a
[...]
declare -a tomb=([0]="első érték" [1]="második érték" [2]="3" [3]="mégegy")
A zárójeles értékadásnál arra kell figyelnünk, hogy a tömb elemeit szóközökkel kell elválasztanunk. Ha több szóból álló értéket szeretnénk megadni, akkor azokat idézőjelek közé kell tenni. A számértékeket és a szóközöket nem tartalmazó szöveges értékeket nem szükséges idézőjelek közé tenni.

És végül, ha csak simán deklarálni szeretnénk egy tömböt, amiben először még nem kívánunk értékeket elhelyezni, akkor ezt az alábbi parancsok valamelyikével végezhetjük:

tomb=()
declare -a tomb=()

A parancsok végén lévő =() értékadások gondoskodnak róla, hogy ha előtte létezett a tömb, akkor kiürítse azt.

Értékek kiolvasása

A példa kedvéért létrehozzuk a tömböt a korábbi értékekkel:

tomb=("első érték" "második érték" 3 mégegy)

Fentebb már láttuk, hogy ez hogyan néz ki a névtérben, most pedig egyesével olvassuk ki az értékeket az indexeik alapján:

echo ${tomb[0]}
echo ${tomb[1]}
echo ${tomb[2]}
echo ${tomb[3]}

A parancsok kimenetei pedig az alábbiak:

első érték
második érték
3
mégegy

Változóként tehát így tudunk hivatkozni az indexelt tömbök egyes elemeire.

Tömbtulajdonságok kiolvasása

A tömb műveletek során gyakran szükség van a tömbök egyéb tulajdonságainak kiolvasására is, mint például az összes elem vagy index kiolvasása, vagy az elemek száma, stb. Ezeket a tulajdonságokat különleges szintaxisok használatával tudjuk kiolvasni, maradva a fenti tömb példánál:

Összes elem kiolvasása egyszerre

echo ${tomb[*]}

vagy

echo ${tomb[@]}

Látszólag ugyanazt a kimenetet adja mindkét szintaxis:

első érték második érték 3 mégegy

Mindkét parancs felsorolja egymás után a tömb összes elemének értékét. Ezzel akkor van gond, ha – a fenti példánkhoz hasonlóan – több szavas értékeket is tárolunk a tömbben. Ilyenkor a kimenet feldolgozása során nem tudjuk megkülönböztetni az elemek közötti határokat az elemeken belüli szóközöktől, tehát használhatatlanná válik a kapott kimenet.

Erre megoldásként használhatjuk az alábbi szintaxisok valamelyikét az előző helyett:

echo ${tomb[*]@Q}

vagy

echo ${tomb[@]@Q}

(Ránézésre még ekkor is ugyanúgy viselkedik mindkét parancs)

'első érték' 'második érték' '3' 'mégegy'

Ebben a kimenetben az értékeket beburkolja aposztrófok közé, amit már könnyen fel tudunk dolgozni.

Vagy pedig ha kimondottan a megjelenítésre szánjuk a tömb elemeit, akkor használhatjuk a printf parancsot, amivel szépen formázhatjuk a felsorolt adatokat:

printf "'%s' " "${tomb[@]}"
'első érték' 'második érték' '3' 'mégegy'

De akár külön sorokban is megjeleníthetjük a tömb elemeit aposztrófok nélkül:

printf "%s\n" "${tomb[@]}"
első érték
második érték
3
mégegy

És itt jön a "*" és a "@" használata közötti különbség:

Ha dupla idézőjelek között kibontjuk a tömböt, akkor a két szintaxis másképp viselkedik:

printf "'%s' " "${tomb[@]}"

Ezt a példát láthattuk az előbb is, ekkor a tömb elemeit külön szavakként kezeli, tehát minden elem külön aposztrófok közé kerül, így a több szavas értékek is:

'első érték' 'második érték' '3' 'mégegy'

A "*" -os változatnál pedig:

printf "'%s' " "${tomb[*]}"

Az tömb összes elemét egy szóként kezeli, azaz egyetlen aposztróf-párba burkolja az elemeket:

'első érték második érték 3 mégegy'

Ennek például a ciklusokban való használatkor van jelentősége.

Ezeknek tudatában már könnyebb a tömb elemek feldolgozása. Például "elkapjuk" egy változóban (XX=$(...) ), stb.

Tartomány kiolvasása

A Bash sokszínűségének köszönhetően lehetőség van a string vágó megoldással a tömbök egy részét is kiolvasni:

echo ${tomb[@]:2:2}

A parancs visszaad a tömb 2. elemétől indulva 2 elemet, azaz a 2. és a 3. elemet (0-val indul az indexelés):

3 mégegy

Összes index kiolvasása egyszerre

echo ${!tomb[@]}
0 1 2 3

Ezzel például ciklusokban dolgozhatunk szépen.

Tömb elemek számának kiolvasása

echo ${#tomb[@]}
4

Tömb elem hosszának a kiolvasása

A tömb megadott indexű elemének a karakterekben mért hosszát pedig az alábbi szintaxissal olvashatjuk ki a fenti példánál maradva:

echo ${#tomb[0]}				# 10
echo ${#tomb[1]}				# 13
echo ${#tomb[2]}				# 1
echo ${#tomb[3]}				# 6

 

 

Tömbök összefűzése

Ha az előző tömbünkhöz szeretnénk még újabb elemeket fűzni, akkor ezt az alábbi módon tehetjük meg:

tomb+=("újabb elem" "mégegy újabb elem")

Ezután a tömb nevű tömbünkez ha lekérdezzük (az aposztrófos módszerrel):

printf "'%s' " "${tomb[@]}"

Akkor Így fog kinézni:

'első érték' 'második érték' '3' 'mégegy' 'újabb elem' 'mégegy újabb elem'

Valamint még így is fűzhetünk újabb elemeket a tömbhöz:

tomb=("${tomb[@]}" "2000" "következő elem")

A tartalma ekkor pedig:

'első érték' 'második érték' '3' 'mégegy' 'újabb elem' 'mégegy újabb elem' '2000' 'következő elem'

Az előző plusz jeles hozzáfűzéshez képest, ilyenkor még annyi szabadságunk is van, hogy az eredeti tömb elemeinek a pozícióját is meghatározhatjuk a felsorolásban, így akár azok elé is szúrhatunk újabb elemeket.

Tömbök használata ciklusokban

Ebben a példában újratöltjük a tömbünket, majd egy for ciklusban végighaladva az elemein kiíratjuk az indexet és a hozzá tartozó értéket. A Shell scriptünk a következő:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
 
tomb=(
    [0]="első elem"
    [1]="Második elem"
    [2]="Harmadik elem"
    [3]=3
    [4]=negyedik
)
 
 
for i in "${!tomb[@]}"; do
    echo "Index: $i, értéke: ${tomb[$i]}"
done

Itt most direkt az indexekkel együtt hoztam létre az elemeket, hogy jobban látható legyen az összerendelés. Valamint látható az is, hogy több sorba tördelve is működik a dolog, így sokkal áttekinthetőbb marad a kód.

Lefuttatva az alábbi kimenetet adja:

Index: 0, értéke: első elem
Index: 1, értéke: Második elem
Index: 2, értéke: Harmadik elem
Index: 3, értéke: 3
Index: 4, értéke: negyedik
Ha itt a ciklusban a "${!tomb[@]}" részt a *-os megoldásra cseréljük "${!tomb[*]}", akkor szintaktikai hibát ad, mivel a dupla idézőjelek között egy szóként bontja ki a *-os változattal a tömb indexeit, ami jelen esetben "0 1 2 3 4" érték lenne. Ilyen indexre pedig nem lehet hivatkozni.
Tehát itt is láthatjuk a két változat közötti működésbeli különbséget.

Tehát a lényeg, hogy a ciklus kiforgatja a ciklus változóba a tömb indexeit, amit így adtunk meg: "${!tomb[@]}". Ezután pedig a ciklusban kiíratjuk az i indexet és utána a tömb hozzá tartozó elemét, amire a ciklus változóval hivatkozunk.

 

A következő oldalon folytatjuk az indexelt tömbök elágazásokban történő használatával.

 

 

Lapozó

Ez a leírás több oldalból áll: