bash: obtém o nome do array do parâmetro para funcionar salvando índices

bash: obtém o nome do array do parâmetro para funcionar salvando índices

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 evallegibilidade. 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.

informação relacionada