Kurze Erklärung der Frage:
Gibt es eine integrierte Bash-Methode, um die Anzahl der Elemente im Bash-Array zu zählen, wobei der Name des Arrays dynamisch ist (dh in einer Variablen gespeichert ist), ohne eine vollständige Kopie des Arrays zu erstellen oder zu verwenden eval
?
Mehr Informationen:
Mit der Bash-Parametersubstitution können Sie Folgendes tun:
- Bestimmen Sie die Länge eines Arrays :
myArr=(A B C); echo ${#myArr[@]}
. - Indirekt auf eine Variable mit Namen verweisen:
NAME=myVar; echo ${!NAME}
(Dies gilt auch für Array-Elemente):
NAME=myArr[1]; echo ${!NAME}
Aber wenn der Name eines Arrays in einer anderen Variablen gespeichert ist, wie kann man die Anzahl der Elemente im Array bestimmen? (Man könnte dies als eine Kombination der beiden oben genannten Parametersubstitutionen betrachten.) Zum Beispiel:
myArr=(A B C D)
NAME=myArr
# Get the number of elements in the array indirectly referenced by NAME.
count=${#$NAME[@]} # This syntax is invalid. What is the right way?
Unten sind mehrere Versuche, die alle fehlschlagen:
# Setup for following attempts:
myArr=(A B C D)
NAME=myArr
EXPR1=$NAME[@] # i.e. EXPR1='myArr[@]'
EXPR2=#$NAME[@] # i.e. EXPR2='#myArr[@]'
# Failed attempts to get the lengh of the array indirectly:
1. count=${#$NAME[@]} # ERROR: bash: ...: bad substitution
2. count=${#!EXPR1} # ERROR: bash: !EXPR}: event not found
3. count=${#\!EXPR1} # ERROR: bash: ...: bad substitution
4. count=${!#EXPR1} # ERROR: bash: ...: bad substitution
5. count=${!EXPR2} # Returns NULL
Ich habe auch einige andere Varianten der oben genannten ausprobiert, aber noch nichts gefunden, was ohne Folgendes funktioniert: (A) Erstellen einer Kopie des Arrays oder (B) Verwenden von eval
.
Arbeitsmethoden:
Es gibt einige Möglichkeiten, dies zu lösen, die wahrscheinlich nicht optimal sind (aber korrigieren Sie mich, wenn ich falsch liege):
Methode 1: Kopieren Sie das Array
Weisen Sie das Array einer anderen (statisch benannten) Variablen zu und ermitteln Sie die Anzahl der darin enthaltenen Elemente.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Methode 2: Verwenden eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Zusammenfassung:
Gibt es eine integrierte Methode (dh Parametersubstitutionssyntax) in bash, um die Länge eines Arrays indirekt zu bestimmen? Wenn nicht, wie geht das am effizientesten? Ich nehme an, es ist die eval
oben beschriebene Methode, aber gibt es Sicherheits- oder Leistungsprobleme mit eval
?
quelle
bash
namerefs? .declare -n ref=abc; abc=(A B C D); printf '%s\n' "${ref[@]}"
time bash -c 'a=(1 a +); c=a; for ((i=0;i<100000;i++)); do eval "echo \${#$c[@]}"; done' > /dev/null
und ähnlich mite=$c[@]; d=("${!e}); echo ${#d[@]}
in der Schleife. Die Auswertung dauerte etwa 90% der Zeit, die für das Kopieren benötigt wurde. Und ich nehme an, dass die Lücke nur größer wird, je größer das Array und seine Elemente sind.Antworten:
Sie sollten dieses Zeug in den Indexbewertungen behandeln. und Sie können indirekt über die Indizes Ihrer Indirektionsvariablen gehen, wenn Sie daraus ein Array machen.
Da
bash
die Indizes auf 0 basieren, wird die Gesamtzahl der Array-Objekte immer um eins höher sein als der höchste festgelegte Index.... der Parameter wird auf das Standardwort erweitert, falls vorhanden.
Wenn einer nicht angegeben ist:
... es wird kein Schaden angerichtet.
In der Schleife verfolge ich eine
$i
ndex-Variable und überprüfe, ob sie mindestens so groß wie$c
ount ist. Wenn es kleiner ist, erweitere ich die$r
eference var auf,a[i]
weil es ein gültiger Index ist, aber wenn es gleich oder größer ist, erweitere ich die$r
ef auf das gesamte$a
Rray.Hier ist es in einer Funktion:
quelle
Bash 4.3 Namerefs sind ein Glücksfall. Sie können dies jedoch tun:
quelle