bash: obtém o nome da matriz do parâmetro para a função com índices salvos

3

Eu tenho uma função para mostrar o índice do elemento escolhido. Eu estou tentando passar um parâmetro para funcionar para usá-lo como um nome de matriz. 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 eu passo para essa função, tem o índice 1 como índice do primeiro elemento (eu preciso disso para ter índices similares aos números de linha, dos quais eu 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 eu estiver executando a função getIndex (), o primeiro elemento da matriz será iniciado a partir do índice 0.

Então, a pergunta é: Existe alguma maneira de passar o nome da matriz no parâmetro para funcionar com os índices salvos da matriz? Ou talvez eu só precise esquecer e adicionar +1 à resposta da função.

    
por King Of Fools 07.10.2013 / 10:30

2 respostas

1

Você está usando essa construção:

b=("${!arrname}")

Isso expande os valores da matriz, criando uma nova matriz b[] com os índices padrão da matriz bash a partir de 0 . Para inicializar corretamente uma cópia da matriz, você precisa restaurar os índices (por exemplo, parsing ou eval -ing a saída de declare -p arrname )

Em vez de fazer uma cópia, uma abordagem melhor é expandir os índices em vez dos valores e iterar pelo array usando-os. Essa abordagem funcionará com matrizes padrão esparsas ou não baseadas em zero (e até matrizes associativas bash4).

A pegadinha (não é sempre) é que o ! está ganhando o dever duplo: 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 o eval legível. Os índices são expandidos em uma matriz, isso não é estritamente necessário, uma lista simples também faria.

Veja também BashFAQ / 006 .

    
por 12.10.2013 / 13:46
1

Matrizes no Bash são baseadas em zero. Eles apenas são. Dito isso, se você sabe que a matriz sempre será indexada por números a partir de 1, basta adicionar +1 ao resultado. Adicione um segundo argumento à função, que informará a qual número iniciar ou incluir no resultado e incluir um padrão sensato nos casos em que o segundo argumento estiver ausente. Ou faça um loop por índices, conforme mr.spuratic sugere.

    
por 07.10.2013 / 13:35