Breve declaração da pergunta:
Existe um método bash interno para contar o número de elementos no array bash, onde o nome do array é dinâmico (ou seja, armazenado em uma variável), sem recorrer a fazer uma cópia completa do array ou usá-lo eval
?
Mais Informações:
Usando a substituição do parâmetro bash, pode-se fazer o seguinte:
- Determinar o comprimento de uma matriz:
myArr=(A B C); echo ${#myArr[@]}
. - Referencie indiretamente uma variável pelo nome:
NAME=myVar; echo ${!NAME}
(isso também se aplica aos elementos da matriz):
NAME=myArr[1]; echo ${!NAME}
Mas se o nome de uma matriz é armazenado em outra variável, como se pode determinar o número de elementos na matriz? (Pode-se considerar isso uma combinação das duas substituições de parâmetro acima.) Por exemplo:
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?
Abaixo estão várias tentativas que todos 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
Eu também tentei algumas outras variantes do acima, mas ainda não encontrei nada que funcione sem: (A) fazer uma cópia da matriz ou (B) usando eval
.
Métodos de trabalho:
Existem algumas maneiras de resolver isso que provavelmente não são ideais (mas corrija-me se estiver errado):
Método 1: Copiar a matriz
Atribua a matriz a outra variável (nomeada estaticamente) e obtenha o número de elementos nela.
EXPR=$NAME[@]
arrCopy=( "${!EXPR}" )
count=${#arrCopy}
Método 2: Usar eval
EXPR="count=\${#$NAME[@]}" # i.e. 'count=${myArr[@]}'
eval $EXPR
# Now count is set to the length of the array
Resumo:
Existe algum método interno (isto é, sintaxe de substituição de parâmetro) no bash para determinar indiretamente o comprimento de uma matriz? Caso contrário, qual é a maneira mais eficiente de fazer isso? Presumo que seja o eval
método acima, mas há problemas de segurança ou desempenho com eval
?
fonte
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
:, e da mesma forma come=$c[@]; d=("${!e}); echo ${#d[@]}
no loop. A avaliação levou cerca de 90% do tempo gasto na cópia. E suponho que essa diferença só aumentará quanto maior a matriz e seus elementos.Respostas:
você deve lidar com essas coisas nos índices. e você pode indiretamente através dos índices da sua variável de indireção, se criar uma matriz.
Como
bash
os índices são baseados em 0, a contagem total de objetos de matriz sempre funcionará com um a mais que o índice definido mais alto e, portanto:... o parâmetro se expande para a palavra padrão, se houver.
Se um não for fornecido:
... não há mal feito.
No loop, acompanho uma
$i
variável ndex e verifico se ela é pelo menos tão grande quanto$c
ount. Quando é menor,$r
expiro a eference var paraa[i]
porque é um índice válido, mas quando é igual ou superior, expiro o$r
ef para todo o$a
raio.Aqui está em uma função:
fonte
bash 4.3 namerefs são uma dádiva de Deus. No entanto, você pode fazer isso:
fonte