Pase la matriz asociativa como lista de parámetros al script

9

En un script tengo una matriz asociativa como:

declare -A VARS=( ["key1"]="value1" ["key2"]="value" )

¿Hay un solo comando para transformar eso en una lista de parámetros en el formulario

--key1=value1 --key2=value2

sin tener que volver a escribir manualmente

 --key1="${VARS[key1]}" --key2="${VARS[key2]}"

El caso de uso que tenía en mente era pasar la matriz a un script como una lista de parámetros, como

my_script.sh $(to_param_list $VARS)

Para ampliar el comentario que hice sobre la respuesta de @Kusalananda, mi caso de uso exacto es el siguiente: tengo un script que se usa para construir un instalador autoextraíble usando makeelf, y este script recibe algunos parámetros que se deben separar:

  • parámetros para el script en sí
  • parámetros para el instalador dentro del instalador autoextraíble

Los scripts luego compilan el instalador de esta manera:

to_param_list installer_param_list installer_param_array
./makeself ./path/to/sourcedir ./path/to/created/installer "My installer" ./path/to/install/inside/package "${installer_param_list[@]}"

Sin embargo, he probado el paso del parámetro con un script de instalación muy simple dentro del paquete:

while ! -z "$1" ; do
    echo "$1"
    shift
done

y pasando una matriz como:

installer_param_array=( ["upgrade-from"]="19 .2.0" ["upgrade-to"]="19.3.0" )

da como resultado esta salida:

--upgrade-to=19.3.0
--upgrade-from=19
.2.0
Matteo Tassinari
fuente
No responde la pregunta, pero otra forma (en bash, una de las etiquetas) es my_script.sh "$(declare -p thearray)$". En myscript.sh lo lees con source /dev/stdin <<<"$1"Entonces lo tienes thearrayen tu guión. Puede tener otros argumentos junto con la matriz. Puede pasar muchas variables: my_script.sh "$(declare -p var1 var2 ...)"en este único argumento.
Dominic108

Respuestas:

13

Con una función auxiliar:

#!/bin/bash

to_param_list () {
    declare -n outlist=$1
    declare -n inhash=$2

    for param in "${!inhash[@]}"; do
        outlist+=( "--$param=${inhash[$param]}" )
    done
}

declare -A my_vars=( ["key1"]="value1" ["key2"]="value" )

to_param_list list my_vars
my_script.sh "${list[@]}"

El comando final en el script anterior se expandiría al equivalente de haber escrito

my_script.sh "--key2=value" "--key1=value1"

La to_param_listfunción toma el nombre de una variable de matriz y el nombre de una variable de matriz asociativa y los utiliza para crear dos variables de "referencia de nombre" en la función (se introdujeron namerefs en la bashversión 4.3). Estos se utilizan para llenar la variable de matriz dada con las claves y los valores en el formato apropiado de la matriz asociativa.

El ciclo en la función se repite "${!inhash[@]}", que es la lista de claves citadas individualmente en su matriz asociativa.

Una vez que la llamada a la función regresa, el script usaría la matriz para llamar a su otro script o comando.

Ejecutando lo anterior con

declare -A my_vars=( ["key1"]="hello world" ["key2"]="some thing" ["key3"]="* * *" )

to_param_list list my_vars
printf 'Arg: %s\n' "${list[@]}"

el script saldría

Arg: --key2=some thing
Arg: --key3=* * *
Arg: --key1=hello world

Esto muestra que las opciones se generan sin la división de palabras o el efecto de bloqueo de nombre de archivo. También muestra que el orden de las claves puede no conservarse, ya que acceder a las claves desde una matriz asociativa lo hará en un orden bastante aleatorio.


Realmente no puede usar una sustitución de comando de forma segura aquí, ya que el resultado sería una sola cadena. Si no se cita, esta cadena se dividiría en caracteres de espacio en blanco (por defecto), lo que dividiría adicionalmente tanto las claves como los valores de su matriz asociativa. El shell también llevaría a cabo el bloqueo de nombre de archivo en las palabras resultantes. Citar dos veces la sustitución del comando no ayudaría, ya que eso resultaría en llamarlo my_script.shcon un solo argumento.


Con respecto a su problema conmakeself :

El makeselfscript hace esto con los argumentos de su script de instalación:

SCRIPTARGS="$*"

Esto guarda los argumentos como una cadena en $SCRIPTARGS(concatenados, separados por espacios). Esto luego se inserta en el archivo autoextraíble tal cual. Para que las opciones se analicen correctamente cuando se vuelven a evaluar (que son cuando se ejecuta el instalador), deberá proporcionar un conjunto adicional de comillas en los valores de los parámetros para que se delimiten correctamente.

installer_param_array=( ["upgrade-from"]="'19 .2.0'" ["upgrade-to"]="'19.3.0'" )

Tenga en cuenta que esto no es un error en mi código. Es solo un efecto secundario de makeselfproducir código shell basado en valores proporcionados por el usuario.

Idealmente, el makeselfscript debería haber escrito cada uno de los argumentos proporcionados con un conjunto adicional de citas a su alrededor, pero no lo hace, presumiblemente porque es difícil saber qué efecto puede tener. En cambio, le deja al usuario proporcionar estas citas adicionales.

Volver a ejecutar mi prueba desde arriba, pero ahora con

declare -A my_vars=( ["key1"]="'hello world'" ["key2"]="'some value'" ["key3"]="'* * *'" )

to_param_list list my_vars
printf 'Arg: %s\n' "${list[@]}"

produce

Arg: --key2='some value'
Arg: --key3='* * *'
Arg: --key1='hello world'

Puede ver que estas cadenas, cuando son reevaluadas por el shell, no se dividirían en espacios.

Obviamente, podría usar su matriz asociativa inicial y en su lugar agregar las comillas en la to_param_listfunción cambiando

outlist+=( "--$param=${inhash[$param]}" )

dentro

outlist+=( "--$param='${inhash[$param]}'" )

Cualquiera de estos cambios en su código incluiría las comillas simples en los valores de las opciones, por lo que sería necesaria una reevaluación de los valores .

Kusalananda
fuente
Probé su solución, sin embargo, si uno de los valores en la matriz asociativa inicial contiene algún espacio, el comando resultante se dividirá
Matteo Tassinari
@MatteoTassinari No, no lo haría. Si lo hace, entonces ha olvidado las comillas dobles en "--$param=${inhash[$param]}"o adentro "${list[@]}", o el script que recibe las opciones hace algo mal al analizarlas.
Kusalananda
Puedo confirmar que usé las comillas como está mostrando, estos parámetros se pasan a github.com/megastep/makeself para crear un instalador que, cuando se ejecuta, invoca un script con los parámetros dados, tal vez en este pasaje algo salga mal
Matteo Tassinari
1
No, no es eso, intentaré editar mi pregunta para mostrar mejor mi caso de uso.
Matteo Tassinari
1
Agregué mi caso de uso real y el error que estoy teniendo
Matteo Tassinari