Kurzusok
/
Bash
Bash
/
Tanterv
/
Többet a tömbökről
Tö

Többet a tömbökről ebben a kurzusban: Bash

{one: "1 feladat", other: "%{count} feladat"}

A(z) Többet a tömbökről fogalomról

A tömböket a Tömbök fejezetben mutattuk be. Ebben a dokumentumban további módokat mutatunk be a tömbök használatára.

Egy tömb elemeinek összefűzése egyetlen stringgé

Az előző, tömbökről szóló fejezetben láttad a "${myarray[@]}" kifejezést az @ indexszel, amellyel a tömböt az egyes elemeire lehet bontani. Néha azonban az összes elemet egyetlen stringgé szeretnéd összefűzni. Ehhez a * indexet használd:

echo "${myarray[*]}"

A kiterjesztést kötelező kettős idézőjelbe tenni.

A Bash az IFS beépített változó első karakterét használja elválasztóként. Alapértelmezés szerint a $IFS szóközből, tabulátorból és újsor karakterből áll.

myarray=(one two three four)
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one two three four"

Az IFS változót módosítva más elválasztó karaktert is használhatunk:

myarray=(one two three four)
IFS=","
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one,two,three,four"
Advanced
Ezt be is csomagolhatjuk egy függvénybe. Kattints a részletekért.
join() {
    local IFS=$1
    shift
    local elements=("$@")
    echo "${elements[*]}"
}

join ":" "${myarray[@]}"     # note, the "@" index
# => "one:two:three:four"

Ha az IFS-t a függvényen belül lokalizáljuk, nem kell elmentenünk a régi értékét, és visszaállítanunk az előző értékére a globális scope-ban.

Finomításként a speciális "$*" paraméter idézőjelben ugyanezt a funkciót nyújtja, így nem kell elmentenünk a függvény argumentumainak másolatát:

join() {
    local IFS=$1
    shift
    echo "$*"
}
Ha nem használunk függvényt, az IFS módosítása egy alshellben jó módja annak, hogy elkerüljük a módosítását az aktuális shellben. Kattints a részletekért.
(IFS=","; echo "${myarray[*]}")

A zárójelek egy alshellt (az aktuális shell másolatát) hoznak létre. Amikor a zárójelek közötti parancsok befejeződnek, az alshell kilép, és a megváltozott IFS változó eltűnik.

Figyelem: ez nem fog működni: IFS="," echo "${myarray[*]}", mert a paraméterkiterjesztés előbb történik meg, mielőtt a shell alkalmazná a módosított IFS változót az echo parancsra.

Tömbszeletek

Talán már láttad a "${variable:offset:length}" paraméterkiterjesztést, amely a változó értékének egy részstringjévé bővül. Ugyanezt megtehetjük tömbökkel is, hogy a tömb egy szeletét kapjuk meg.

myarray=(one two three four)

subarray=("${myarray[@]:0:2}")
declare -p subarray
# => declare -a subarray=([0]="one" [1]="two")

subarray=("${myarray[@]:1:3}")
declare -p subarray
# => declare -a subarray=([0]="two" [1]="three" [2]="four")

A hossz rész elhagyása azt jelenti, hogy „a kezdőponttól a tömb végéig”:

subarray=("${myarray[@]:2}")
declare -p subarray
# => declare -a subarray=([0]="three" [1]="four")

Tömb átadása függvénynek

Ez nem olyan egyszerű, mint más nyelvekben, amiket esetleg ismersz. Két fő módszer van arra, hogy egy tömböt átadjunk egy függvénynek.

Az elemek átadása

Az első módszernél a tömb összes értékét átadod, és a függvényben egy lokális tömbbe gyűjtöd őket.

myfunc() {
    local array_copy=("$@")
    # do stuff with array_copy
    declare -p array_copy
}

array_original=(11 22 33 44)
myfunc "${array_original[@]}"

A függvény tömbje az értékek másolatát tartalmazza. A függvényben a tömbön végzett módosítások nem jelennek meg a külső scope-ban.

A tömb nevének átadása

Ez a módszer jobban hasonlít a „referencia szerinti átadás” lehetőségéhez, amit más nyelvekből ismerhetsz. A tömb nevét adod át stringként. A függvény létrehoz egy lokális változót a „nameref” attribútummal. Ez a lokális tömb és a globális tömb (amelynek a nevét átadtuk) ugyanaz a tömb.

myfunc() {
    # note the `-n` option
    local -n local_array=$1

    # do stuff with local_array
    for i in "${!local_array[@]}"; do
        printf '%d => %s\n' "$i" "${local_array[i]}"
    end

    # we can mutate it
    local_array+=(55 66 77)
}

array_original=(11 22 33 44)
myfunc "array_original"

# show the mutated array
declare -p array_original
# => declare -a array_original=([0]="11" [1]="22" [2]="33" [3]="44" [4]="55" [5]="66" [6]="77")

A nameref asszociatív tömbökkel és „skalár” változókkal (amelyek stringértéket tartalmaznak) is működik.

Note

A függvényen belül a declare -p local_array nem túl hasznos. Csak ennyit ír ki: declare -n local_array="array_original". A tömb részletes adatait úgy kapod meg, ha megvizsgálod az átadott tömb nevét: declare -p "$1"

Caution

Ügyelj rá, hogy a lokális tömb neve térjen el az átadott tömb nevétől. A kód ettől még működik, de „körkörös névre hivatkozás” figyelmeztetéseket ír ki, például ilyeneket:

myfunc() {
    local -n a=$1
    local IFS=,
    echo "${a[*]}"
}

# same name as the function's local variable
a=(one two three)
myfunc a
bash: local: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
one,two,three

A pozicionális paraméterek „tömbszerűek”

Azokban a shellekben, amelyek csak a POSIX szabványnak próbálnak megfelelni (például az ash és a dash), nincsenek tömbök. A legközelebbi megoldás a pozicionális paraméterek használata.

  • A pozicionális paramétereket index alapján éred el: $1, $2 stb.
  • A "$@" kifejezéssel az egyes elemekre bonthatók
  • A "$*" kifejezéssel egyetlen stringgé fűzhetők össze
  • A paraméterek számát a $# adja meg

A set paranccsal rendelhetsz nekik értékeket:

set -- one two three
set -- "$@" four

for item in "$@"; do
    echo "do something with $item"
done

Ha a célod „hordozható” shell szkriptek írása, akkor a pozicionális paramétereket használod majd egy értékekből álló „lista” tárolására.

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg