bash: obtiene el nombre de la matriz del parámetro para funcionar guardando índices

bash: obtiene el nombre de la matriz del parámetro para funcionar guardando índices

Tengo una función para mostrar el índice del elemento elegido. Estoy intentando pasar un parámetro a la función para usarlo como nombre de matriz. Esto 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

}

Pero la matriz, cuyo nombre le paso a esta función, tiene el índice 1 como índice del primer elemento (necesito que tenga índices similares a los números de línea, de los cuales obtengo patrones en la matriz:

a=1
while read line; do
    if [[ $line =~ ^[0-9] ]]; then
        avg[$a]=`echo $line | awk '{print $6}'`
        ((a++));    
    fi

Y si estoy ejecutando la función getIndex() el primer elemento de la matriz comienza desde el índice 0.

Entonces, la pregunta es: ¿Hay alguna forma de pasar el nombre de la matriz en el parámetro para que funcione guardando los índices de la matriz? O tal vez simplemente necesito olvidarme de eso y agregar +1 a la función respuesta.

Respuesta1

Estás usando esta construcción:

b=("${!arrname}")

Esto amplía lavaloresde la matriz, creando una nueva matriz b[]conlos índices de matriz predeterminados de bash a partir de 0. Para inicializar correctamente una copia de la matriz, necesitará restaurar los índices (por ejemplo, analizando o evalmodificando la salida de declare -p arrname)

En lugar de hacer una copia, un mejor enfoque es ampliar laíndicesen lugar de los valores, e iterar sobre la matriz usándolos. Este enfoque funcionará con matrices estándar dispersas o de base distinta de cero (e incluso matrices asociativas bash4).

El problema (no siempre existe) es que !cumple una doble función: su uso en dirección indirecta ${!name}no es compatible con su uso para expandir índices de matriz ${!arrname[@]}, por lo que tenemos que usarlo eval.

Aquí hay una versión modificada que implementa esto:

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
}

Tenga en cuenta el uso de printf -v var ...(bash-3.1+) para intentar mantener la evallegibilidad. Los índices se expanden en una matriz, esto no es estrictamente necesario, una lista plana también sería suficiente.

Ver tambiénBashFAQ/006.

Respuesta2

Las matrices en Bash tienen base cero. Simplemente lo son. Dicho esto, si tusaberque la matriz siempre estará indexada por números que comiencen desde 1, simplemente agregue +1 al resultado. Agregue un segundo argumento a la función, que le dirá desde qué número comenzar o agregar al resultado, y agregue un valor predeterminado sensato para los casos en los que falta el segundo argumento. O recorrer los índices comoseñor espuráticosugiere.

información relacionada