bash: Array-Namen vom Parameter zur Funktion abrufen und dabei Indizes speichern

bash: Array-Namen vom Parameter zur Funktion abrufen und dabei Indizes speichern

Ich habe eine Funktion, um den Index des ausgewählten Elements anzuzeigen. Ich versuche, der Funktion einen Parameter zu übergeben, um ihn als Array-Namen zu verwenden. Das funktioniert:

getIndex() {
arrname=$1[@]
b=("${!arrname}")
index=1; while ((index<${#b[@]})); do
    if [[ "${b[$index]}" = "$VALUE" ]]; then
        echo "index is $index"; return
    fi  
        ((index++)); done

}

Aber das Array, dessen Namen ich an diese Funktion übergebe, hat den Index 1 als Index des ersten Elements (ich brauche Indizes ähnlich den Zeilennummern, aus denen ich Muster im Array erhalte:

a=1
while read line; do
    if [[ $line =~ ^[0-9] ]]; then
        avg[$a]=`echo $line | awk '{print $6}'`
        ((a++));    
    fi

Und wenn ich die Funktion getIndex() ausführe, beginnt das erste Element des Arrays beim Index 0.

Die Frage ist also: Gibt es eine Möglichkeit, den Array-Namen als Parameter an die Funktion zu übergeben und dabei die Array-Indizes zu speichern? Oder vielleicht muss ich es einfach vergessen und der Funktionsantwort +1 hinzufügen.

Antwort1

Sie verwenden diese Konstruktion:

b=("${!arrname}")

Dies erweitert dieWertedes Arrays, Erstellen eines neuen Arrays b[]mitdie Bash-Standard-Array-Indizes beginnend bei 0. Um eine Kopie des Arrays richtig zu initialisieren, müssten Sie die Indizes wiederherstellen (z. B. durch Parsen oder eval-ing der Ausgabe von declare -p arrname).

Anstatt eine Kopie zu erstellen, ist es besser, dieIndizesanstelle der Werte, und iterieren Sie mit diesen über das Array. Dieser Ansatz funktioniert mit spärlichen oder nicht auf Null basierenden Standardarrays (und sogar assoziativen Arrays in Bash4).

Der Haken (ist da nicht immer der Fall) besteht darin, dass es eine !Doppelfunktion hat: Seine Verwendung bei der Indirektion ${!name}ist nicht mit seiner Verwendung zum Erweitern von Array-Indizes kompatibel ${!arrname[@]}, daher müssen wir verwenden eval.

Hier ist eine geänderte Version, die dies implementiert:

getIndex2() {
  local arrname=$1 iidx idxs index ival val
  printf -v iidx '"${!%s[@]}"' "$arrname"
  eval "idxs=($iidx)"
  for index in "${idxs[@]}"; do
    printf -v ival '${%s[%s]}' "$arrname" "$index"
    eval "val=$ival"
    if [[ "${val}" = "$VALUE" ]]; then
        echo "index is $index"; return   
    fi
  done
}

Beachten Sie die Verwendung von printf -v var ...(bash-3.1+), um die Lesbarkeit zu erhalten eval. Die Indizes werden in ein Array erweitert. Dies ist nicht unbedingt erforderlich, eine flache Liste würde auch ausreichen.

Siehe auchBashFAQ/006.

Antwort2

Arrays in Bash sind nullbasiert. Das sind sie einfach. Das heißt, wenn Siewissendass das Array immer mit Zahlen beginnend bei 1 indiziert wird, addieren Sie einfach +1 zum Ergebnis. Fügen Sie der Funktion ein zweites Argument hinzu, das ihr mitteilt, bei welcher Zahl sie beginnen oder welche Zahl sie zum Ergebnis hinzufügen soll, und fügen Sie einen sinnvollen Standardwert für Fälle hinzu, in denen das zweite Argument fehlt. Oder führen Sie eine Schleife über Indizes aus, wieHerr Spuraticschlägt vor.

verwandte Informationen