Eu tenho uma função para mostrar o índice do elemento escolhido. Estou tentando passar um parâmetro para funcionar para usá-lo como nome de array. Isso funciona:
getIndex() {
arrname=$1[@]
b=("${!arrname}")
index=1; while ((index<${#b[@]})); do
if [[ "${b[$index]}" = "$VALUE" ]]; then
echo "index is $index"; return
fi
((index++)); done
}
Mas o array, cujo nome passo para esta função, tem o índice 1 como índice do primeiro elemento (preciso que isso tenha índices semelhantes aos números das linhas, dos quais obtenho padrões no array:
a=1
while read line; do
if [[ $line =~ ^[0-9] ]]; then
avg[$a]=`echo $line | awk '{print $6}'`
((a++));
fi
E se estou executando a função getIndex() o primeiro elemento do array começa no índice 0.
Então, a questão é: Existe alguma maneira de passar o nome do array no parâmetro para funcionar salvando os índices do array? Ou talvez eu só precise esquecer isso e adicionar +1 à resposta da função.
Responder1
Você está usando esta construção:
b=("${!arrname}")
Isto expande ovaloresdo array, criando um novo array b[]
comos índices da matriz padrão do bash começando em 0. Para inicializar adequadamente uma cópia do array, você precisaria restaurar os índices (por exemplo, analisando ou eval
-ing a saída de declare -p arrname
)
Em vez de fazer uma cópia, uma abordagem melhor é expandir oíndicesem vez dos valores, e itere sobre a matriz usando-os. Essa abordagem funcionará com matrizes padrão esparsas ou com base diferente de zero (e até mesmo matrizes associativas bash4).
O problema (nem sempre existe) é que está !
exercendo uma função dupla: seu uso indireto ${!name}
não é compatível com seu uso para expandir índices de array ${!arrname[@]}
, então temos que usar eval
.
Aqui está uma versão modificada que implementa isso:
getIndex2() {
local arrname=$1 iidx idxs index ival val
printf -v iidx '"${!%s[@]}"' "$arrname"
eval "idxs=($iidx)"
for index in "${idxs[@]}"; do
printf -v ival '${%s[%s]}' "$arrname" "$index"
eval "val=$ival"
if [[ "${val}" = "$VALUE" ]]; then
echo "index is $index"; return
fi
done
}
Observe o uso de printf -v var ...
(bash-3.1+) para tentar manter a eval
legibilidade. Os índices são expandidos em um array, isso não é estritamente necessário, uma lista simples também serviria.
Veja tambémBashFAQ/006.
Responder2
Matrizes no Bash são baseadas em zero. Eles simplesmente são. Dito isto, se vocêsaberque o array sempre será indexado por números começando em 1, basta adicionar +1 ao resultado. Adicione um segundo argumento à função, que dirá de qual número começar ou adicionar ao resultado, e adicione um padrão sensato para casos em que o segundo argumento está faltando. Ou faça um loop sobre os índices comosenhor.espuráticosugere.