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
?
fuente
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
y de manera similar cone=$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.Respuestas:
deberías manejar esas cosas en el índice evals. y puede indirecta a través de los índices de su variable de indirección si la convierte en una matriz.
Debido a que
bash
los índices están basados en 0, el recuento total de objetos de matriz siempre funcionará en uno más que el índice establecido más alto, y así:... el parámetro se expande a la palabra predeterminada si se proporciona alguno.
Si no se proporciona uno:
... no hay daño hecho.
En el bucle, sigo una
$i
variable ndex y verifico si es al menos tan grande como$c
ount. Cuando es menor,$r
amplío la eferencia vara[i]
porque es un índice válido, pero cuando es igual o mayor, expando el$r
ef a toda la$a
matriz.Aquí está en una función:
fuente
bash 4.3 namerefs son un regalo del cielo. Sin embargo, puedes hacer esto:
fuente