¿Cuál es la forma más correcta de pasar una matriz a una función?

8

Considere que tengo una matriz muy grande $large_list, ¿hay alguna manera de escribir una función que tome la matriz como argumento? Por ejemplo:

echo_idx_array () {
    arr="$1"
    idx="$2"

    echo "${arr[$idx]}"
}

¿Cuál es la estrategia habitual para hacer algo así? Intenté dar la variable $large_listpero estaba vacía.

Estoy dispuesto a modificar la función para adaptarla a cualquier cambio en la lista de argumentos.

Para el registro, estoy usando ksh88, y estoy buscando respuestas lo más portátiles posible.


EDITAR : Hasta ahora, lo mejor que se me ocurre es recorrer la matriz y enviar cada elemento como argumento a la función. Esto parece increíblemente feo y propenso a errores, sin mencionar que seguramente alcanzará algún límite rápidamente. Esto es lo que hice:

foo () {
    echo $*
}

cmd="foo "
while [[ $i -lt $MAX_ARR_SIZE ]]; do
    cmd="$cmd ${large_list[$i]}"
    ((i=i+1))
done

eval $cmd

¿No hay algo mejor que hacer?

rahmu
fuente
1
No estoy familiarizado con ksh88, pero si necesita pasar toda la matriz por valor, ¿lo ha intentado func "${array[@]}"? Si solo necesita pasar un elemento, simplemente pase el elemento; no es necesario hacerlo más complicado al pasar una matriz y un índice.
jw013
Probé
1
Estaba cansado y confundido. Había probado "${array[$@]}. Su sugerencia realmente funciona. Mea culpa.
rahmu

Respuestas:

10

Para pasar los elementos de la matriz como argumentos a la función, use la sintaxis ksh para expandir los elementos de la matriz como una lista.

work_on_array "${myarray[@]}"

El [@]sufijo lo convierte en una expansión de matriz. Las comillas dobles protegen a cada elemento de una mayor expansión (división y globalización). El resultado de la expansión no es, en general, una palabra como suele ser con comillas dobles, sino tantas palabras como elementos en la matriz.

El N -ésimo elemento de la matriz es entonces . Para acceder a él, debe usar ; ver Usar una referencia de variable "dentro" de otra variable${N}eval

Gilles 'SO- deja de ser malvado'
fuente
Gracias. Pregunta: si el resultado de la expansión no es una palabra, ¿por qué se necesitan las comillas? ¿Se pueden omitir? ¿Estás aplicando tu consejo de "siempre cita a menos que tengas una buena razón para no hacerlo"? : p
rahmu
1
@rahmu Las citas son necesarias para evitar dividir y pegar en elementos individuales. Considere myarray=("hello world" wibble)(2 elementos, el primero de los cuales contiene un espacio): work_on_array "${myarray[@]}"pasa 2 parámetros hello worldy wibble; work_on_array ${myarray[@]}pases 2 parámetros hello, worldy wibble. Y con myarray=(*), work_on_array ${myarray[@]}pasa la lista de archivos en el directorio actual. (Por lo tanto, este es uno de los muchos casos en los que mi consejo hace una diferencia práctica.)
Gilles 'SO- deja de ser malvado'
Corrígeme si me equivoco, pero creo que hay un error tipográfico en lo que escribiste: la expansión sin comillas pasa 3 params, no 2.
rahmu
1
@rahmu Hay dos parámetros: miedo y sorpresa ... y eficiencia despiadada. (En otras palabras, tienes razón, no es un error tipográfico: hello, worldy wibblehace 3 parámetros.)
Gilles 'SO siendo parada del mal'
4

Hay una manera en bash 4.3+, que probablemente proviene de ksh:

echo_idx_array () # array index
{
    local -n array=$1     # add nameref attribute
    local idx=$2
    echo "${array[idx]}"
}

$ names=(one two three four)
$ echo_idx_array names 2
three
$ days=([monday]=eggs [tuesday]=bread [sunday]=jam)    # associative array
$ echo_idx_array days sunday
jam

Ver también declare -n.

Edouard Thiel
fuente
Huh, interesante Sí, esto vino de ksh, y funciona en mksh sin modificaciones.
mirabilos
1

Depende del Korn Shell ... las versiones recientes de AT&T ksh93 y mksh lo admiten:

function echo_idx_array {
    nameref arr=$1
    idx=$2

    echo "${arr[idx]}"
}

set -A test -- a b c
echo_idx_array test 1

En mi shell actual, esto produce la salida "b".

mirabilos
fuente