Was ist der korrekteste Weg, um ein Array an eine Funktion zu übergeben?

8

Angenommen, ich habe ein sehr großes Array. Gibt $large_listes eine Möglichkeit, eine Funktion zu schreiben, die das Array als Argument verwendet? Zum Beispiel:

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

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

Was ist die übliche Strategie, um so etwas zu tun? Ich habe versucht, die Variable anzugeben, $large_listaber sie war leer.

Ich bin bereit, die Funktion zu ändern, um sie an jede Änderung in der Argumentliste anzupassen.

Für die Aufzeichnung verwende ich ksh88 und suche nach Antworten, die so portabel wie möglich sind.


EDIT : Bisher war das Beste, was ich finden konnte, das Array zu durchlaufen und jedes Element als Argument an die Funktion zu senden. Dies scheint unglaublich hässlich und fehleranfällig zu sein, ganz zu schweigen davon, dass es schnell an ein Limit stoßen wird. Folgendes habe ich getan:

foo () {
    echo $*
}

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

eval $cmd

Gibt es nicht etwas Besseres zu tun?

Rahmu
quelle
1
Ich bin nicht mit ksh88 vertraut, aber wenn Sie das gesamte Array als Wert übergeben müssen, haben Sie es versucht func "${array[@]}"? Wenn Sie nur ein Element übergeben müssen, übergeben Sie einfach das Element - Sie müssen es nicht durch Übergeben eines Arrays und eines Index komplizierter machen.
jw013
Ich habe die von Ihnen vorgeschlagene Syntax ausprobiert, aber sie hat nicht funktioniert :(
Rahmu
1
Ich war müde und verwirrt. Ich hatte versucht "${array[$@]}. Ihr Vorschlag funktioniert tatsächlich. Mea culpa.
Rahmu

Antworten:

10

Um die Array-Elemente als Argumente an die Funktion zu übergeben, verwenden Sie die ksh-Syntax, um die Elemente des Arrays als Liste zu erweitern.

work_on_array "${myarray[@]}"

Das [@]Suffix macht dies zu einer Array-Erweiterung. Die doppelten Anführungszeichen schützen jedes Element vor weiterer Erweiterung (Teilen und Globbing). Das Ergebnis der Erweiterung ist im Allgemeinen nicht ein Wort, wie es normalerweise in doppelten Anführungszeichen steht, sondern so viele Wörter, wie Elemente im Array vorhanden sind.

Das N- te Element des Arrays ist dann . Um darauf zuzugreifen, müssen Sie verwenden ; Siehe Verwenden einer Variablenreferenz "innerhalb" einer anderen Variablen${N}eval

Gilles 'SO - hör auf böse zu sein'
quelle
Vielen Dank. Frage: Wenn das Ergebnis der Erweiterung nicht ein Wort ist, warum werden die Anführungszeichen benötigt? Können sie weggelassen werden? Wenden Sie nur Ihren Rat an: "Immer zitieren, es sei denn, Sie haben einen guten Grund, dies nicht zu tun"? : p
rahmu
1
@rahmu Die Anführungszeichen werden benötigt, um das Teilen und Globbing einzelner Elemente zu vermeiden. Betrachten Sie myarray=("hello world" wibble)(2 Elemente, von denen das erste ein Leerzeichen enthält): work_on_array "${myarray[@]}"Übergibt 2 Parameter hello worldund wibble; work_on_array ${myarray[@]}2 Parameter übergibt hello, worldund wibble. Und mit myarray=(*), wird work_on_array ${myarray[@]}die Liste der Dateien im aktuellen Verzeichnis übergeben. (Daher ist dies einer der vielen Fälle, in denen mein Rat einen praktischen Unterschied macht.)
Gilles 'SO - hör auf böse zu sein'
Korrigieren Sie mich, wenn ich falsch liege , aber ich glaube, dass das, was Sie geschrieben haben, einen Tippfehler enthält: Die nicht zitierte Erweiterung besteht 3 Parameter, nicht 2.
Rahmu
1
@rahmu Es gibt zwei Parameter: Angst und Überraschung… und rücksichtslose Effizienz. (Mit anderen Worten, du hast recht, es ist ein Tippfehler: hello, worldund wibble3 Parameter machen.)
Gilles ‚SO- Anschlag, der böse‘
4

In Bash 4.3+ gibt es einen Weg, der wahrscheinlich von ksh kommt:

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

Siehe auch declare -n.

Edouard Thiel
quelle
Huh, interessant. Ja, das kam von ksh und funktioniert in mksh unverändert.
Mirabilos
1

Hängt von der Korn Shell ab… die neuesten Versionen von AT & T ksh93 und mksh unterstützen dies:

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

    echo "${arr[idx]}"
}

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

In meiner aktuellen Shell gibt dies "b" aus.

Mirabilos
quelle