Breve affermazione della domanda:
Esiste un metodo bash incorporato per contare il numero di elementi nell'array bash, in cui il nome dell'array è dinamico (ovvero memorizzato in una variabile), senza ricorrere alla creazione di una copia completa dell'array o all'utilizzo eval
?
Maggiori informazioni:
Usando la sostituzione dei parametri bash, si può fare quanto segue:
- Determinare la lunghezza di un array:
myArr=(A B C); echo ${#myArr[@]}
. - Indirettamente fare riferimento a una variabile per nome:
NAME=myVar; echo ${!NAME}
(questo vale anche per gli elementi dell'array):
NAME=myArr[1]; echo ${!NAME}
Ma se il nome di un array è memorizzato in un'altra variabile, come si può determinare il numero di elementi nell'array? (Si potrebbe considerare questa una combinazione delle due sostituzioni di parametri precedenti). Ad esempio:
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?
Di seguito sono riportati più tentativi che tutti FAIL:
# 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
Ho anche provato alcune altre varianti di quanto sopra, ma non ho ancora trovato nulla che funzioni senza: (A) facendo una copia dell'array o (B) usando eval
.
Metodi di lavoro:
Ci sono un paio di modi per risolvere questo problema che probabilmente non sono ottimali (ma correggimi se sbaglio):
Metodo 1: copia l'array
Assegna l'array a un'altra variabile (denominata staticamente) e ottieni il numero di elementi in essa contenuti.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Metodo 2: utilizzare eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Sommario:
Esiste un metodo incorporato (ad es. Sintassi di sostituzione dei parametri) in bash per determinare indirettamente la lunghezza di un array? In caso contrario, qual è il modo più efficiente per farlo? Presumo che sia il eval
metodo sopra, ma ci sono problemi di sicurezza o prestazioni con eval
?
time bash -c 'a=(1 a +); c=a; for ((i=0;i<100000;i++)); do eval "echo \${#$c[@]}"; done' > /dev/null
e similmente con e=$c[@]; d=("${!e}); echo ${#d[@]}
nel loop. La valutazione ha richiesto circa il 90% del tempo impiegato dalla copia. E suppongo che il divario aumenterà solo con l'aumentare dell'array e dei suoi elementi.