Passer le tableau associatif comme liste de paramètres au script

9

Dans un script, j'ai un tableau associatif comme:

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

Existe-t-il une seule commande pour transformer cela en une liste de paramètres sous la forme

--key1=value1 --key2=value2

sans avoir à réécrire manuellement

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

le cas d'utilisation que j'avais en tête était de passer le tableau à un script comme une liste de paramètres, comme

my_script.sh $(to_param_list $VARS)

Pour développer le commentaire que j'ai fait sur la réponse de @Kusalananda, mon cas d'utilisation exact est le suivant: j'ai un script qui est utilisé pour construire un programme d'installation auto-extractible en utilisant make-make, et ce script reçoit certains paramètres qui doivent être séparés entre:

  • paramètres pour le script lui-même
  • paramètres pour l'installateur dans l'installateur auto-extractible

Les scripts construisent ensuite l'installateur comme ceci:

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[@]}"

Cependant, j'ai testé le passage de paramètres avec un script d'installation très simple à l'intérieur du package:

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

et en passant un tableau comme:

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

donne cette sortie:

--upgrade-to=19.3.0
--upgrade-from=19
.2.0
Matteo Tassinari
la source
Il ne répond pas à la question, mais une autre façon (en bash, une des balises) est my_script.sh "$(declare -p thearray)$". En myscript.sh vous le lisez avec source /dev/stdin <<<"$1"ensuite vous avez thearraydans votre script. Vous pouvez avoir d'autres arguments à côté du tableau. Vous pouvez passer de nombreuses variables: my_script.sh "$(declare -p var1 var2 ...)"dans ce seul argument.
Dominic108

Réponses:

13

Avec une fonction d'assistance:

#!/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[@]}"

La commande finale dans le script ci-dessus s'étendrait à l'équivalent d'avoir écrit

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

La to_param_listfonction prend le nom d'une variable de tableau et le nom d'une variable de tableau associatif et les utilise pour créer deux variables de «référence de nom» dans la fonction (les références de nom ont été introduites dans la bashversion 4.3). Celles-ci sont ensuite utilisées pour remplir la variable de tableau donnée avec les clés et les valeurs au format approprié à partir du tableau associatif.

La boucle de la fonction itère sur "${!inhash[@]}", qui est la liste des clés entre guillemets individuels dans votre tableau associatif.

Une fois l'appel de fonction de retour, le script utilise le tableau pour appeler votre autre script ou commande.

Exécution de ce qui précède avec

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

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

le script afficherait

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

Cela montre que les options sont générées sans que le fractionnement de mot ou le remplacement de nom de fichier n'entrent en vigueur. Cela montre également que l'ordre des clés peut ne pas être conservé, car l'accès aux clés à partir d'un tableau associatif le fera dans un ordre assez aléatoire.


Vous ne pouvez pas vraiment utiliser une substitution de commande en toute sécurité ici car le résultat serait une seule chaîne. Si elle n'est pas entre guillemets, cette chaîne sera ensuite divisée en caractères d'espacement (par défaut), ce qui divisera également les clés et les valeurs de votre tableau associatif. L'interpréteur de commandes exécuterait également un remplacement de nom de fichier sur les mots résultants. La citation double de la substitution de commande n'aiderait pas car cela entraînerait l'appel de votre my_script.shavec un seul argument.


Concernant votre problème avecmakeself :

Le makeselfscript fait cela avec les arguments de votre script d'installation:

SCRIPTARGS="$*"

Cela enregistre les arguments sous forme de chaîne $SCRIPTARGS(concaténés, séparés par des espaces). Celui-ci est ensuite inséré tel quel dans l'archive auto-extractible. Pour que les options soient correctement analysées lorsqu'elles sont réévaluées (ce qu'elles sont lors de l'exécution du programme d'installation), vous devrez fournir un ensemble supplémentaire de guillemets dans les valeurs des paramètres pour qu'elles soient correctement délimitées.

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

Notez que ce n'est pas un bug dans mon code. C'est juste un effet secondaire de la makeselfproduction de code shell basé sur des valeurs fournies par l'utilisateur.

Idéalement, le makeselfscript devrait avoir écrit chacun des arguments fournis avec un ensemble supplémentaire de guillemets autour d'eux, mais ce n'est pas le cas, probablement parce qu'il est difficile de savoir quel effet cela peut avoir. Au lieu de cela, il laisse à l'utilisateur le soin de fournir ces devis supplémentaires.

Relancer mon test d'en haut, mais maintenant avec

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

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

produit

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

Vous pouvez voir que ces chaînes, lorsqu'elles sont réévaluées par le shell, ne sont pas divisées en espaces.

De toute évidence, vous pouvez utiliser votre tableau associatif initial et ajouter à la place les guillemets dans la to_param_listfonction en changeant

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

dans

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

L'une ou l'autre de ces modifications de votre code inclurait les guillemets simples dans les valeurs des options, donc une réévaluation des valeurs deviendrait nécessaire .

Kusalananda
la source
J'ai essayé votre solution, cependant, si l'une des valeurs du tableau associatif de départ contient de l'espace, la commande résultante sera interrompue
Matteo Tassinari
@MatteoTassinari Non, ce ne serait pas le cas. Si c'est le cas, vous avez oublié les guillemets doubles dans "--$param=${inhash[$param]}"ou dans "${list[@]}", ou le script qui reçoit les options fait quelque chose de mal en les analysant.
Kusalananda
Je peux confirmer que j'ai utilisé les guillemets comme vous le montrez, ces paramètres sont passés à github.com/megastep/makeself pour créer un programme d'installation qui, lors de son exécution, appelle un script avec les paramètres donnés, peut-être que dans ce passage quelque chose ne va pas
Matteo Tassinari
1
Non, ce n'est pas ça, je vais essayer de modifier ma question pour mieux montrer mon cas d'utilisation.
Matteo Tassinari
1
J'ai ajouté mon cas d'utilisation réel et l'erreur que je rencontre
Matteo Tassinari