Bref énoncé de la question:
Existe-t-il une méthode bash intégrée pour compter le nombre d'éléments dans le tableau bash, où le nom du tableau est dynamique (c'est-à-dire stocké dans une variable), sans recourir à une copie complète du tableau ou à l'utilisation eval
?
Plus d'information:
En utilisant la substitution de paramètres bash, on peut faire ce qui suit:
- Déterminer la longueur d'un tableau:
myArr=(A B C); echo ${#myArr[@]}
. - Référencez indirectement une variable par son nom:
NAME=myVar; echo ${!NAME}
(cela s'applique également aux éléments du tableau):
NAME=myArr[1]; echo ${!NAME}
Mais si le nom d'un tableau est stocké dans une autre variable, comment déterminer le nombre d'éléments dans le tableau? (On pourrait considérer cela comme une combinaison des deux substitutions de paramètres ci-dessus.) Par exemple:
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?
Vous trouverez ci-dessous plusieurs tentatives qui ont toutes échoué:
# 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
J'ai également essayé d'autres variantes de ce qui précède, mais je n'ai encore rien trouvé qui fonctionne sans: (A) faire une copie du tableau ou (B) en utilisant eval
.
Les méthodes de travail:
Il existe deux façons de résoudre ce problème qui ne sont probablement pas optimales (mais corrigez-moi si je me trompe):
Méthode 1: copiez le tableau
Attribuez le tableau à une autre variable (nommée statiquement) et obtenez le nombre d'éléments qu'elle contient.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Méthode 2: utiliser eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Résumé:
Existe-t-il une méthode intégrée (c'est-à-dire une syntaxe de substitution de paramètres) dans bash pour déterminer indirectement la longueur d'un tableau? Sinon, quelle est la manière la plus efficace de procéder? Je suppose que c'est la eval
méthode ci-dessus, mais y a-t-il des problèmes de sécurité ou de performances avec eval
?
la source
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
:, et de même avece=$c[@]; d=("${!e}); echo ${#d[@]}
dans la boucle. L'évaluation a pris environ 90% du temps nécessaire à la copie. Et je suppose que l'écart ne fera qu'augmenter plus le tableau et ses éléments seront grands.Réponses:
vous devez gérer ce genre de choses dans les index. et vous pouvez indirectement via les indices de votre variable d'indirection si vous en faites un tableau.
Étant donné que
bash
les indices de sont basés sur 0, le nombre total d'objets de tableau correspondra toujours à un de plus que l'index défini le plus élevé, et donc:... le paramètre se développe jusqu'au mot par défaut s'il en est.
Si aucun n'est fourni:
... il n'y a pas de mal.
Dans la boucle, je
$i
dépiste une variable ndex et vérifie si elle est au moins aussi grande que$c
ount. Quand il est moindre,$r
j'étends la var eferencea[i]
car c'est un index valide, mais quand il est égal ou supérieur, j'étends$r
ef à l'ensemble du$a
rray.Le voici dans une fonction:
la source
bash 4.3 namerefs est une aubaine. Cependant, vous pouvez le faire:
la source