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 eval
modificando 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 eval
legibilidad. 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.