Tracce
/
Bash
Bash
/
Programma
/
Altro sugli array
Al

Altro sugli array in Bash

{one: "1 esercizio", many: "%{count} esercizi", other: "%{count} esercizi"}

Informazioni su Altro sugli array

Abbiamo introdotto gli array nel capitolo Array. Questo documento mostrerà altri modi per usare gli array.

Concatenare gli elementi di un array in un'unica stringa

Nel capitolo precedente sugli array hai visto "${myarray[@]}", con l'indice @, usato per espandere l'array nei singoli elementi. A volte però vuoi unire tutti gli elementi in un'unica stringa. Per farlo, usa l'indice *:

echo "${myarray[*]}"

È necessario racchiudere l'espansione tra virgolette doppie.

Bash usa il primo carattere della variabile builtin IFS come carattere separatore. Per impostazione predefinita, $IFS è composto da spazio, tabulazione e a capo.

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

Possiamo modificare la variabile IFS per usare un carattere separatore diverso:

myarray=(one two three four)
IFS=","
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one,two,three,four"
Advanced
Possiamo incapsularlo in una funzione. Clicca per i dettagli.
join() {
    local IFS=$1
    shift
    local elements=("$@")
    echo "${elements[*]}"
}

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

Localizzare IFS nella funzione significa che non dobbiamo salvare il vecchio valore e ripristinarlo al suo valore precedente nello scope globale.

Come affinamento, il parametro speciale "$*", quando è tra virgolette, ha la stessa funzionalità, quindi non serve salvare una copia degli argomenti della funzione:

join() {
    local IFS=$1
    shift
    echo "$*"
}
Senza usare una funzione, modificare IFS in una subshell è un buon modo per evitare di modificarlo nella shell corrente. Clicca per i dettagli.
(IFS=","; echo "${myarray[*]}")

Le parentesi creano una subshell (una copia della shell corrente). Quando i comandi all'interno delle parentesi terminano, la subshell esce e la variabile IFS modificata scompare.

Nota che questo non funzionerà: IFS="," echo "${myarray[*]}", l'espansione dei parametri viene eseguita per prima, prima che la shell applichi la variabile IFS modificata al comando echo.

Slicing degli array

Potresti aver visto l'espansione dei parametri "${variable:offset:length}" che si espande in una sottostringa del valore della variabile. Possiamo fare la stessa cosa con gli array per espandere una slice dell'array.

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")

Omettere la parte relativa alla lunghezza significa "dall'offset alla fine dell'array":

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

Passare un array a una funzione

Non è così semplice come in altri linguaggi che potresti conoscere. Ci sono due tecniche principali per passare un array a una funzione.

Passare gli elementi

Nella prima tecnica passi tutti i valori dell'array e li raccogli in un array locale dentro la funzione.

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

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

L'array della funzione contiene una copia dei valori. Le modifiche apportate all'array nella funzione non si riflettono nello scope esterno.

Passare il nome dell'array

Questa tecnica assomiglia di più alla capacità di "passaggio per riferimento" che potresti conoscere da altri linguaggi. Passi il nome dell'array come stringa. La funzione creerà una variabile locale con l'attributo "nameref". Questo array locale e l'array globale (il cui nome abbiamo passato) sono lo stesso array.

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")

I nameref funzionano anche con gli array associativi e con le variabili "scalari" (che contengono un valore di tipo stringa).

Note

All'interno della funzione, declare -p local_array non è molto utile. Emetterà semplicemente declare -n local_array="array_original". Puoi ottenere informazioni dettagliate sull'array ispezionando il nome dell'array passato: declare -p "$1"

Caution

Fai attenzione che l'array locale abbia un nome diverso dall'array passato. Il codice funzionerà comunque, ma emetterà avvisi come "circular name reference" in questo modo:

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

I parametri posizionali sono simili agli array

Nelle shell che mirano a conformarsi solo allo standard POSIX (come ash e dash) non esistono gli array. La cosa più vicina a cui puoi arrivare è usare i parametri posizionali.

  • I parametri posizionali si accedono per indice: $1, $2, ecc.
  • Si espandono in singoli elementi con "$@"
  • Si concatenano in un'unica stringa con "$*"
  • Il numero di parametri è $#

Usa il comando set per assegnare loro dei valori:

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

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

Se il tuo obiettivo è scrivere script shell "portabili", userai i parametri posizionali per memorizzare un "array" di valori.

Modifica tramite GitHub Il collegamento si apre in una nuova finestra o scheda