Breve declaración de la pregunta:
¿Existe un método bash incorporado para contar el número de elementos en la matriz bash, donde el nombre de la matriz es dinámico (es decir, almacenado en una variable), sin recurrir a hacer una copia completa de la matriz o usarlo eval
?
Más información:
Usando la sustitución de parámetros bash, uno puede hacer lo siguiente:
- Determinar la longitud de una matriz:
myArr=(A B C); echo ${#myArr[@]}
. - Indirectamente hacer referencia a una variable por su nombre:
NAME=myVar; echo ${!NAME}
(esto también se aplica a los elementos de la matriz):
NAME=myArr[1]; echo ${!NAME}
Pero si el nombre de una matriz se almacena en otra variable, ¿cómo se puede determinar el número de elementos en la matriz? (Uno podría considerar esto como una combinación de las dos sustituciones de parámetros anteriores). Por ejemplo:
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?
A continuación hay varios intentos que FALLAN:
# 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
También probé algunas otras variantes de lo anterior, pero todavía no he encontrado nada que funcione sin: (A) hacer una copia de la matriz o (B) usando eval
.
Métodos de trabajo:
Hay un par de formas de resolver esto que probablemente no sean óptimas (pero corríjame si me equivoco):
Método 1: copie la matriz
Asigne la matriz a otra variable (con nombre estático) y obtenga el número de elementos en ella.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Método 2: uso eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Resumen:
¿Hay algún método incorporado (es decir, sintaxis de sustitución de parámetros) en bash para determinar la longitud de una matriz indirectamente? Si no, ¿cuál es la forma más eficiente de hacer esto? Supongo que es el eval
método anterior, pero ¿existen problemas de seguridad o rendimiento eval
?
time bash -c 'a=(1 a +); c=a; for ((i=0;i<100000;i++)); do eval "echo \${#$c[@]}"; done' > /dev/null
y de manera similar con e=$c[@]; d=("${!e}); echo ${#d[@]}
en el bucle. La evaluación tomó aproximadamente el 90% del tiempo que se tardó en copiar. Y supongo que esa brecha solo aumentará cuanto más grande sea la matriz y sus elementos.