Qual è il modo più corretto per passare un array a una funzione?


8

Considera che ho un array molto grande $large_list, c'è un modo per scrivere una funzione che prenderà l'array come argomento? Per esempio:

echo_idx_array () {
    arr="$1"
    idx="$2"

    echo "${arr[$idx]}"
}

Qual è la solita strategia per fare qualcosa del genere? Ho provato a dare la variabile $large_listma era vuota.

Sono disposto a modificare la funzione per adattarla a qualsiasi modifica nell'elenco degli argomenti.

Per la cronaca, sto usando ksh88 e cerco risposte il più portatili possibile.


EDIT : Finora il meglio che potevo inventare è quello di passare in rassegna l'array e inviare ogni elemento come argomento alla funzione. Questo sembra incredibilmente brutto e soggetto a errori, per non parlare del fatto che è destinato a raggiungere rapidamente un certo limite. Ecco cosa ho fatto:

foo () {
    echo $*
}

cmd="foo "
while [[ $i -lt $MAX_ARR_SIZE ]]; do
    cmd="$cmd ${large_list[$i]}"
    ((i=i+1))
done

eval $cmd

Non c'è qualcosa di meglio da fare?


1
Non ho familiarità con ksh88, ma se hai bisogno di passare l'intero array per valore, hai provato func "${array[@]}"? Se hai solo bisogno di passare un elemento, basta passare l'elemento - non è necessario renderlo più contorto passando un array e un indice.
jw013,

Ho provato la sintassi da te suggerita, ma non ha funzionato :(
rahmu

1
Ero stanco e confuso. Ci avevo provato "${array[$@]}. Il tuo suggerimento funziona davvero. Colpa mia.
Rahmu,

Risposte:


10

Per passare gli elementi dell'array come argomenti alla funzione, utilizzare la sintassi ksh per espandere gli elementi dell'array come elenco.

work_on_array "${myarray[@]}"

Il [@]suffisso rende questo un ampliamento di array. Le doppie virgolette proteggono ogni elemento da un'ulteriore espansione (divisione e globbing). Il risultato dell'espansione non è in genere una parola come di solito è tra virgolette doppie, ma quante più parole ci sono elementi nella matrice.

Il N -esimo elemento dell'array è poi . Per accedervi, è necessario utilizzare ; vedi Usa un riferimento di variabile "dentro" un'altra variabile${N}eval


Grazie. Domanda: se il risultato dell'espansione non è una parola, perché sono necessarie le virgolette? Possono essere omessi? Stai solo applicando il tuo consiglio di "citare sempre a meno che tu non abbia una buona ragione per non farlo"? : p
rahmu,

1
@rahmu Le virgolette sono necessarie per evitare spaccature e strappi sui singoli elementi. Considerare myarray=("hello world" wibble)(2 elementi, il primo dei quali contiene uno spazio): work_on_array "${myarray[@]}"passa 2 parametri hello worlde wibble; work_on_array ${myarray[@]}passa 2 parametri hello, worlde wibble. E con myarray=(*), work_on_array ${myarray[@]}passa l'elenco dei file nella directory corrente. (Quindi questo è uno dei molti casi in cui il mio consiglio fa una differenza pratica.)
Gilles 'SO- smetti di essere malvagio' il

Correggimi se sbaglio, ma credo che ci sia un refuso in quello che hai scritto: l'espansione non quotata supera 3 parametri, non 2.
rahmu

1
@rahmu Ci sono due parametri: paura e sorpresa ... ed efficienza spietata. (In altre parole, hai ragione, c'è un errore di battitura: hello, worlde wibblefai 3 parametri.)
Gilles 'SO-tappa è male'

4

C'è un modo in bash 4.3+, che probabilmente viene da ksh:

echo_idx_array () # array index
{
    local -n array=$1     # add nameref attribute
    local idx=$2
    echo "${array[idx]}"
}

$ names=(one two three four)
$ echo_idx_array names 2
three
$ days=([monday]=eggs [tuesday]=bread [sunday]=jam)    # associative array
$ echo_idx_array days sunday
jam

Vedi anche declare -n.


Eh, interessante. Sì, questo proviene da ksh e funziona in mksh non modificato.
mirabilos,

1

Dipende da Korn Shell ... le recenti versioni AT&T ksh93 e mksh supportano questo:

function echo_idx_array {
    nameref arr=$1
    idx=$2

    echo "${arr[idx]}"
}

set -A test -- a b c
echo_idx_array test 1

Nella mia shell corrente, questo produce "b".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.