Tömbök kezelése és használata a Shell scriptekben (2. oldal)

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

A 2. oldal tartalma

 

Folytatás

A leírás első oldalán megnéztük hogyan hozhatjuk létre az indexelt tömböket és hogyan írhatunk bele adatokat, vagy olvashatunk ki belőle. Ezen az oldalon folytatjuk az indexelt tömbökkel való ismerkedést a tömbök elágazásokban illetve függvényekben történő felhasználásával.

 

 

Indexelt tömbök

Tömbök használata elágazásokban

A tömbök használata az elágazásokban többféleképpen is lehetséges.

Logikai vizsgálat

A logikai vizsgálat során a tömb megadott indexű elemének meglétét vizsgáljuk, ami a következőképpen történik:

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
#!/bin/bash
 
tomb=(
    [0]="első elem"
    [1]="Második elem"
    [2]="Harmadik elem"
    [3]=3
    [4]=negyedik
)
 
 
# Rövid vizsgálat:
[ ${tomb[3]} ] && echo "létezik" || echo "nincs ilyen indexű elem"
# Rövid vizsgálat fordított logikával:
[ ! ${tomb[3]} ] && echo "nincs ilyen indexű elem" || echo "létezik"
 
echo
 
# Több soros vizsgálat:
if [ ${tomb[3]} ]; then
    echo "létezik"
    # További kódsorok, ha létezik az elem
else
    echo "nincs ilyen indexű elem"
    # További kódsorok, ha nem létezik az elem
fi

Itt három példát is láthatunk a vizsgálatra. Az első kettő az egysoros vizsgálat, ahol egyszerűen csak kiírjuk a megfelelő eredményt, és utána egy többsoros változat, ahol az elágazásokban további kódsorokat is elhelyezhetünk.

A logikai megfordítást a ! jellel a többsoros változatban is alkalmazhatjuk, ha például csak a hamis ágra van szükségünk az ellenőrzés során. Ilyenkor az else rész nélkül rövidebb kódot készíthetünk.

Érték vizsgálat

Érték vizsgálatkor pedig a tömb adott elemének értékét hasonlítjuk össze valamivel:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/bin/bash
 
tomb=(
    [0]="első elem"
    [1]="Második elem"
    [2]="Harmadik elem"
    [3]=3
    [4]=negyedik
)
 
echo -------------------------------
echo Karakter alapú vizsgálatok:
echo -------------------------------
 
echo "Rövid vizsgálatok:"
 
# Rövid vizsgálatok többféleképpen:
[ ${tomb[3]} = 3 ] && echo "megfelelő érték" || echo "nem megfelelő érték"
[ "${tomb[3]}" = 3 ] && echo "megfelelő érték" || echo "nem megfelelő érték"
[ "${tomb[0]}" = "első elem" ] && echo "megfelelő érték" || echo "nem megfelelő érték"
 
# Rövid vizsgálatok fordított logikával:
[ ! ${tomb[3]} = 3 ] && echo "nem megfelelő érték" || echo "megfelelő érték"
[ ! "${tomb[3]}" = 3 ] && echo "nem megfelelő érték" || echo "megfelelő érték"
[ ! "${tomb[0]}" = "első elem" ] && echo "nem megfelelő érték" || echo "megfelelő érték"
 
# Becsapós vizsgálat
echo "Becsapós..."
# Ennek a kiértékelése hamis lesz, mivel karakterláncként hasonlítja össze a két oldalt.
[[ 3 < 11 ]] && echo "igaz" || echo "hamis (becsapós példa)"
# Ez alapján az alábbi tömb elem összehasonlítás is hamis lesz:
[[ ${tomb[3]} < 11 ]] && echo "igaz" || echo "hamis (becsapós példa)"
 
 
# Több soros vizsgálat:
echo "Több soros vizsgálat:"
if [ "${tomb[4]}" = "negyedik" ]; then
    echo "megfelelő érték"
    # További kódsorok, ha megfelelő az érték
else
    echo "nem megfelelő érték"
    # További kódsorok, ha nem megfelelő az érték
fi
 
echo
echo -------------------------------
echo Numerikus vizsgálatok:
echo -------------------------------
 
# Rövid használat:
echo "Rövid használat:"
(( ${tomb[3]} == 3 )) && echo "Igaz feltétel" || echo "Hamis feltétel"
(( ${tomb[3]} > 1 )) && echo "Igaz feltétel" || echo "Hamis feltétel"
 
# Ez a fenti becsapós vizsgálat helyesen használt numerikus változata, itt már igaz lesz a kiértékelés:
(( 3 < 11 )) && echo "igaz (helyesen használt példa)" || echo "hamis"
# Ennek megfelelően a tömbbel végzett összehasonlítás is igaz lesz:
(( ${tomb[3]} < 11 )) && echo "igaz (helyesen használt példa)" || echo "hamis"
 
 
 
# Több soros:
echo "Több soros:"
if (( ${tomb[3]} < 11 )); then
    echo "Igaz feltétel"
    # elágazás további sorai...
else
    echo "Hamis feltétel"
    # elágazás további sorai...
fi

Itt is több példában láthatjuk az érték ellenőrzéseket. És még variálható sokféleképpen. (A példaprogramot egy az egyben bemásolhatjuk és futtathatjuk a shell-ben)

A karakter alapú vizsgálatoknál könnyű hibába csúszni, mivel a fenti becsapós példának megfelelően számokat is össze lehet hasonlítani. Viszont ilyenkor is karakterláncként hasonlítja össze a két oldalt, ami sok esetben matematikailag helytelen eredményt ad, ami attól még a karakterláncok szempontjából helyes.
Ezt csak a szemléletesség kedvéért tettem bele, hogy ha tömbökkel (vagy bármilyen egyéb változókkal) végzünk vizsgálatokat, akkor ügyeljünk az azokban lévő értékek típusainak megfelelő összehasonlítására.

Tömbök használata függvényekben

Egy vagy több tömböt is átadhatunk a függvényeknek paraméterként, amiket aztán a függvényben felhasználhatunk.

Paraméterek egy tömbként kezelése

Vannak esetek, amikor arra van szükség, hogy a függvény minden paraméterét egyetlen tömbbe gyűjtsük össze. Ezek között lehetnek egyéni értékek vagy akár tömbök is, amelyek további értékmezőket tartalmaznak. A következő példa jól szemlélteti ennek a kivitelezését:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
 
# Indexelt tömb feltöltése néhány számértékkel:
tomb=(100 200 500 1000 150 350 220)
 
function fuggveny {
    tomb2=("$@")                    # Összes paraméter begyűjtése egy másik tömbbe
 
    for i in "${!tomb2[@]}"; do
        ertek=${tomb2[$i]}
        printf "%3s%12s\n" "$i:" $ertek
    done
}
 
# Függvény hívása a vegyes tömb és számérték paraméterekkel
fuggveny 1 2 3 "${tomb[@]}" 4 5 6

A példaprogram kimenete:

 0:           1
 1:           2
 2:           3
 3:         100
 4:         200
 5:         500
 6:        1000
 7:         150
 8:         350
 9:         220
10:           4
11:           5
12:           6

Itt tehát látható, hogy a vegyesen megadott paraméterek mindegyike ugyanúgy bekerült a függvényben használt tömbbe.

A megoldás azon alapul, hogy a függvény hívásakor a megadott paraméterek között a tömböt a "${tomb[@]}" formában adjuk meg, ami a korábban már megismert módon (több szavas elemekkel is működően) kibontja a tömb összes elemét, azaz olyan, mintha egyesével adtuk volna meg azokat a függvénynek. Majd a függvényben pedig a $@ operátorral kibontott paramétereket egy tömbbe töltjük be.

Ez a módszer például olyankor jöhet jól, amikor egy függvényt úgy kell elkészíteni, hogy nem ismerjük előre a kapott paraméterek számát, viszont fel kell tudnunk dolgozni azokat.

A gyakorlat kedvéért a következő példaprogramban a függvény a numerikus paramétereit szintén egy tömbbe gyűjti össze, majd kiszámítja azok összegét, átlagát és meghatározza a minimum és maximum értéküket:

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
36
37
38
39
40
41
42
#!/bin/bash
 
# Indexelt tömb feltöltése néhány számértékkel:
tomb=(100 200 500 1000 150 350 220)
 
# Összeget, átlagot és szélső értékekeket kiszámító függvény:
function ertekek {
    tomb2=("$@")                # Kimásoljuk egy másik változóba a teljes paramétersort
 
    # Változók kezdőértékei
    osszeg=0                    # Ebben lesz az összeg
    atlag=0                     # Ebben lesz az átlag
    minimum=${tomb2[0]}         # Legkisebb elem
    maximum=${tomb2[0]}         # Legnagyobb elem
 
    echo "Tömb elemek:"
    echo "--------------"
    for i in "${!tomb2[@]}"; do
        ertek=${tomb2[$i]}      # Változónév rövidítés, hogy áttekinthetőbb legyen
        printf "%3s%12s\n" "$i:" $ertek
 
        (( ertek > maximum )) && maximum=$ertek
        (( ertek < minimum )) && minimum=$ertek
        (( osszeg = osszeg + $ertek ))
 
    done
    # Átlag kiszámítása:
    #(( atlag = osszeg / ${#tomb[@]} ))
    # A Bash alapból csak egész számokkal dolgozik, így az előző osztás nem lenne pontos
    # Helyette a bc-vel számítjuk ki 2 tizedes pontossággal, amit egy subshell-ből olvasunk ki:
    atlag=$(echo "scale=2; $osszeg / ${#tomb2[@]}" | bc)
 
    echo "---------------"
    printf "%-10s%6s\n" "Összeg:" $osszeg
    printf "%-10s%6s\n" "Átlag:" $atlag
    printf "%-9s%6s\n" "Minimum:" $minimum
    printf "%-9s%6s\n" "Maximum:" $maximum
    echo "---------------"
}
 
# Függgvény hívása
ertekek "${tomb[@]}" 1 2 3

Ennek a kimenete:

Tömb elemek:
--------------
 0:         100
 1:         200
 2:         500
 3:        1000
 4:         150
 5:         350
 6:         220
 7:           1
 8:           2
 9:           3
---------------
Összeg:    2526
Átlag:   252.60
Minimum:      1
Maximum:   1000
---------------

Itt is megfigyelhetjük, hogy mindegy hogy egyéni számértékeket adunk a függvénynek vagy tömböt, valamint ezek sorrendjét is szabadon választhatjuk meg, a függvény feldolgoz minden kapott számértéket.

Ezzel a megoldással dinamikusan kezelhetjük a kapott paramétereket, nem számít azok mennyisége, viszont vannak korlátai is: nem tudjuk külön kezelni a tömb paramétereket, így azokat csak közös feladatokra tudjuk felhasználni a függvényben. Ezért szükség lehet olyan megoldásra is, ahol a kapott tömb paramétereket külön dolgozzuk fel.

 

 

Több tömb paraméter külön kezelése

Lehetőség van a függvényen belül arra is, hogy a kapott tömb paramétereket külön kezeljük, ezáltal a függvénynek adott adat paraméterek mellett még más opciókat, beállító parancsokat, stb is adhatunk. A következő példa ezt mutatja be:

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
36
37
38
39
40
41
#!/bin/bash
 
# 1. indexelt tömb feltöltése néhány adattal:
tomb1=(100 200 500 "több szavas" "másik három szavas")
 
# 2. indexelt tömb feltöltése néhány számértékkel:
tomb2=("másik tömb" 2000 "ebben is vannak több szavas elemek" 2500 3000 "a-b c")
 
 
function fuggveny {
    # param1 és param2 nevű tömbök deklarálása a paraméterekben kapott NEVEK alapján
    declare -n param1=$1
    declare -n param2=$2
 
    echo "-----------------------------"
    echo "1. Paramétertömb kilistázása:"
    echo "-----------------------------"
    for i in "${!param1[@]}"; do
        ertek=${param1[$i]}
        echo "$i: $ertek"
    done
 
    echo
    echo "-----------------------------"
    echo "2. Paramétertömb kilistázása:"
    echo "-----------------------------"
    for i in "${!param2[@]}"; do
        ertek=${param2[$i]}
        echo "$i: $ertek"
    done
 
    echo
    echo "-----------------------------"
    echo "Egyéb paraméterek kiírása:   "
    echo "-----------------------------"
    echo "3. paraméter: $3"
    echo "4. paraméter: $4"
}
 
# Függvény hívása a vegyes paraméterekkel
fuggveny tomb1 tomb2 "beállítás 1" "beállítás 2"

A kimenete pedig:

-----------------------------
1. Paramétertömb kilistázása:
-----------------------------
0: 100
1: 200
2: 500
3: több szavas
4: másik három szavas

-----------------------------
2. Paramétertömb kilistázása:
-----------------------------
0: másik tömb
1: 2000
2: ebben is vannak több szavas elemek
3: 2500
4: 3000
5: a-b c

-----------------------------
Egyéb paraméterek kiírása:   
-----------------------------
3. paraméter: beállítás 1
4. paraméter: beállítás 2

Ennek a módszernek a lényege az, hogy a függvény paramétereiben a tömbök név szerint kerültek átadásra, nem pedig a kibontott értékeikkel. Majd a függvényben a 12. és 13. sorokban a kapott nevek alapján hozzuk létre a belső változókat.

Ennek a megközelítésnek viszont annyi a hátránya, hogy itt fix paraméter sorrenddel kell dolgozni a függvényben, tehát ahogy belekódoljuk az algoritmusba, olyan sorrendben kell érkezniük a paramétereknek is, különben hibák lépnek fel. Persze vannak módszerek, amikkel végigjárhatjuk az összes paramétert, és megvizsgálhatjuk azok típusát, de ez már egy másik történet...

Tömb elemek és tömbök törlése

Egy adott elemet a következő szintaxissal törölhetünk:

unset tomb[4]

Ilyenkor a dollárjel és a kapcsos zárójel nélkül hivatkozunk a változóra, mint tárolóra, nem pedig a benne lévő értékre.

Az egész tömb törléséhez pedig adjuk ki a következőt:

unset tomb

Itt is hasonlóan a dollárjel és kapcsos nélkül hivatkozunk, csak magára az egész tömbre.

 

következő oldalon folytatjuk az asszociatív tömbökkel való megismerkedéssel...

 

 

Lapozó

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