¿Cómo puedo pasar una matriz como parámetro a una función bash?
Nota: Después de no encontrar una respuesta aquí en Stack Overflow, publiqué mi solución algo cruda yo mismo. Solo permite pasar una matriz y es el último elemento de la lista de parámetros. En realidad, no está pasando la matriz en absoluto, sino una lista de sus elementos, que se vuelven a ensamblar en una matriz mediante called_function (), pero funcionó para mí. Si alguien conoce una mejor manera, siéntase libre de agregarla aquí.
Respuestas:
Puede pasar múltiples matrices como argumentos usando algo como esto:
hará eco:
Edición / notas: (de los comentarios a continuación)
descTable
yoptsTable
se pasan como nombres y se expanden en la función. Por lo tanto, no$
se necesita cuando se dan como parámetros.descTable
etc., ya que se define a loslocal
locales, ya que los locales son visibles para las funciones que llaman.!
en${!1}
expande la variable arg 1.declare -a
solo hace explícita la matriz indexada, no es estrictamente necesaria.fuente
Nota: Esta es la solución un tanto cruda que publiqué yo mismo, después de no encontrar una respuesta aquí en Stack Overflow. Solo permite pasar una matriz y es el último elemento de la lista de parámetros. En realidad, no está pasando la matriz en absoluto, sino una lista de sus elementos, que se vuelven a ensamblar en una matriz mediante called_function (), pero funcionó para mí. Un poco más tarde, Ken publicó su solución, pero yo guardé la mía aquí como referencia "histórica".
Mejorado por TheBonsai, gracias.
fuente
called_function "${#array[@]}" "${array[@]}" "${#array2[@]}" "${array2[@]}"
etc ... aún con algunas restricciones obvias, pero en realidad, es mejor resolver el problema de una manera que el idioma admita, en lugar de tratar de doblar el idioma para que funcione como está acostumbrado en otros idiomas.Comentando sobre la solución de Ken Bertelson y respondiendo a Jan Hettich:
Cómo funciona
la
takes_ary_as_arg descTable[@] optsTable[@]
línea en latry_with_local_arys()
función envía:descTable
yoptsTable
que son accesibles para latakes_ary_as_arg
función.takes_ary_as_arg()
función recibedescTable[@]
yoptsTable[@]
como cadenas, eso significa$1 == descTable[@]
y$2 == optsTable[@]
.Al comienzo de la
takes_ary_as_arg()
función, utiliza la${!parameter}
sintaxis, que se denomina referencia indirecta o, a veces, doble referencia , lo que significa que, en lugar de usar$1
el valor de, usamos el valor del valor expandido de$1
, por ejemplo:igualmente para
$2
.argAry1=("${!1}")
creaargAry1
como una matriz (los corchetes siguientes=
) con el expandidodescTable[@]
, al igual que escribir allíargAry1=("${descTable[@]}")
directamente. Eldeclare
no es necesario.NB: Vale la pena mencionar que la inicialización de la matriz utilizando este formulario de paréntesis inicializa la nueva matriz de acuerdo con el separador de campo interno
IFS
o que es, por defecto , la pestaña , la nueva línea y el espacio . en ese caso, dado que usaba notación, cada elemento es visto por sí mismo como si fuera citado (contrario a ).[@]
[*]
Mi reserva con el
En
BASH
, el alcance de la variable local es la función actual y cada función secundaria llamada desde ella, esto se traduce en el hecho de que latakes_ary_as_arg()
función "ve" esasdescTable[@]
yoptsTable[@]
matrices, por lo que está funcionando (ver explicación anterior).Siendo ese el caso, ¿por qué no mirar directamente esas variables? Es como escribir allí:
Consulte la explicación anterior, que solo copia
descTable[@]
los valores de la matriz de acuerdo con la corrienteIFS
.En resumen
También quiero enfatizar el comentario anterior de Dennis Williamson: las matrices dispersas (las matrices sin todas las claves definidas - con "agujeros" en ellas) no funcionarán como se esperaba - perderíamos las claves y "condensaríamos" la matriz.
Dicho esto, veo el valor para la generalización, las funciones pueden obtener las matrices (o copias) sin conocer los nombres:
para copias reales: podemos usar una evaluación para las claves, por ejemplo:
y luego un bucle que los usa para crear una copia. Nota: aquí
!
no se utiliza su evaluación previa indirecta / doble, sino que en el contexto de matriz devuelve los índices de matriz (claves).descTable
yoptsTable
cadenas (sin[@]
), podríamos usar la matriz en sí (como en referencia) coneval
. para una función genérica que acepta matrices.fuente
Array1
, luego conArray2
, pasar los nombres de la matriz se vuelve útil.El problema básico aquí es que los desarrolladores de bash que diseñaron / implementaron matrices realmente atornillaron al chucho. Decidieron que
${array}
era solo una mano corta${array[0]}
, lo cual fue un grave error. Especialmente cuando consideras eso${array[0]}
no tiene significado y evalúa la cadena vacía si el tipo de matriz es asociativo.La asignación de una matriz toma la forma
array=(value1 ... valueN)
donde el valor tiene la sintaxis[subscript]=string
, asignando así un valor directamente a un índice particular en la matriz. Esto hace que pueda haber dos tipos de matrices, indexadas numéricamente e indexadas hash (llamadas matrices asociativas en lenguaje bash). También lo hace para que pueda crear dispersas matrices indexadas numéricamente. Dejar la[subscript]=
parte es una abreviatura para una matriz indexada numéricamente, comenzando con el índice ordinal de 0 e incrementándose con cada nuevo valor en la instrucción de asignación.Por lo tanto,
${array}
debe evaluar a toda la matriz, índices y todo. Debe evaluar al inverso de la declaración de asignación. Cualquier estudiante de tercer año de CS debería saber eso. En ese caso, este código funcionaría exactamente como podría esperar:Luego, pasar matrices por valor a funciones y asignar una matriz a otra funcionaría como lo dicta el resto de la sintaxis de shell. Pero debido a que no hicieron esto correctamente, el operador de asignación
=
no funciona para las matrices, y las matrices no se pueden pasar por valor a funciones o subcapas o salida en general (echo ${array}
) sin código para analizarlo todo.Entonces, si se hubiera hecho bien, el siguiente ejemplo mostraría cómo la utilidad de las matrices en bash podría ser sustancialmente mejor:
El resultado resultante debe ser:
Luego, las matrices podrían usar el operador de asignación y pasarlas por valor a las funciones e incluso a otros scripts de shell. Se almacena fácilmente mediante la salida a un archivo y se carga fácilmente desde un archivo a un script.
Por desgracia, nos ha decepcionado un equipo de desarrollo de bash de otro modo superlativo.
Como tal, para pasar una matriz a una función, en realidad solo hay una opción, y es usar la función nameref:
dará como resultado la siguiente salida:
Como esto pasa por referencia, también puede asignar a la matriz en la función. Sí, la matriz a la que se hace referencia debe tener un alcance global, pero eso no debería ser un gran problema, teniendo en cuenta que se trata de scripts de shell. Para pasar una matriz indexada asociativa o dispersa por valor a una función, es necesario incluir todos los índices y los valores en la lista de argumentos (no demasiado útil si se trata de una matriz grande) como cadenas individuales como esta:
y luego escribir un montón de código dentro de la función para volver a ensamblar la matriz.
fuente
local -n
es mejor y más actualizada que la respuesta aceptada. Esta solución también funcionará para una variable de cualquier tipo. El ejemplo que figura en esta respuesta se puede acortar alocal -n ARR=${1}
. Sin embargo, la-n
opción paralocal
/declare
solo está disponible en Bash versión 4.3 y superior.funky ARR
), el shell dará una advertenciacircular name reference
, porque básicamente la función intentará hacerlolocal -n ARR=ARR
. Buena discusión sobre este tema.La respuesta de DevSolar tiene un punto que no entiendo (tal vez tiene una razón específica para hacerlo, pero no se me ocurre ninguno): establece la matriz de los parámetros posicionales elemento por elemento, iterativa.
Un acercamiento más fácil sería
fuente
Ejemplo
fuente
Una manera fácil de pasar varias matrices como parámetro es usar una cadena separada por caracteres. Puedes llamar a tu script de esta manera:
Luego, puede extraerlo en su código de esta manera:
De esta manera, puede pasar múltiples matrices como parámetros y no tiene que ser los últimos parámetros.
fuente
Este funciona incluso con espacios:
fuente
Con algunos trucos, puede pasar parámetros con nombre a funciones, junto con matrices.
El método que desarrollé le permite acceder a los parámetros pasados a una función como esta:
En otras palabras, no solo puedes llamar a tus parámetros por sus nombres (lo que compensa un núcleo más legible), sino que también puedes pasar matrices (y referencias a variables; ¡esta función solo funciona en bash 4.3!). Además, las variables asignadas están todas en el ámbito local, igual que $ 1 (y otras).
El código que hace que esto funcione es bastante ligero y funciona tanto en bash 3 como en bash 4 (estas son las únicas versiones con las que lo he probado). Si está interesado en más trucos como este que hacen que el desarrollo con bash sea mucho más fácil y fácil, puede echar un vistazo a mi Bash Infinity Framework , el código a continuación fue desarrollado para ese propósito.
fuente
Solo para agregar a la respuesta aceptada, ya que descubrí que no funciona bien si el contenido de la matriz es algo así como:
En este caso, cada miembro de la matriz se divide, por lo que la matriz que ve la función es equivalente a:
Para que este caso funcione, la forma en que encontré es pasar el nombre de la variable a la función, luego usar eval:
Solo mi 2 ©
fuente
Tan feo como es, aquí hay una solución alternativa que funciona siempre y cuando no pase una matriz explícitamente, sino una variable correspondiente a una matriz:
Estoy seguro de que alguien puede llegar a una implementación más clara de la idea, pero he encontrado que esta es una mejor solución que pasar una matriz como
"{array[@]"}
y luego acceder internamente usandoarray_inside=("$@")
. Esto se complica cuando hay otros posicionales /getopts
parámetros. En estos casos, primero tuve que determinar y luego eliminar los parámetros no asociados con la matriz usando alguna combinación deshift
y eliminación de elementos de la matriz.Una perspectiva purista probablemente ve este enfoque como una violación del lenguaje, pero hablando pragmáticamente, este enfoque me ha ahorrado mucho dolor. En un tema relacionado, también uso
eval
para asignar una matriz construida internamente a una variable nombrada de acuerdo con un parámetrotarget_varname
que paso a la función:eval $target_varname=$"(${array_inside[@]})"
Espero que esto ayude a alguien.
fuente
Requisito : Función para encontrar una cadena en una matriz.
Esta es una ligera simplificación de la solución de DevSolar, ya que utiliza los argumentos pasados en lugar de copiarlos.
fuente
Mi respuesta corta es:
${test_array[*]}
y${test_array2[*]}
debe estar rodeado por "", de lo contrario, fallará.fuente