Übergeben Sie das assoziative Array als Parameterliste an das Skript

9

In einem Skript habe ich ein assoziatives Array wie:

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

Gibt es einen einzigen Befehl, um dies in eine Parameterliste im Formular umzuwandeln?

--key1=value1 --key2=value2

ohne manuell neu schreiben zu müssen

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

Der Anwendungsfall, an den ich gedacht hatte, bestand darin, das Array als Liste von Parametern an ein Skript zu übergeben

my_script.sh $(to_param_list $VARS)

Um den Kommentar zu der Antwort von @Kusalananda zu erweitern, lautet mein genauer Anwendungsfall wie folgt: Ich habe ein Skript, mit dem ein selbstextrahierendes Installationsprogramm mit makeelf erstellt wird, und dieses Skript empfängt einige Parameter, zwischen denen Folgendes getrennt werden soll:

  • Parameter für das Skript selbst
  • Parameter für das Installationsprogramm im selbstextrahierenden Installationsprogramm

Die Skripte erstellen dann das Installationsprogramm wie folgt:

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

Ich habe die Parameterübergabe jedoch mit einem sehr einfachen Installationsskript im Paket getestet:

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

und Übergeben eines Arrays wie:

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

Ergebnisse in dieser Ausgabe:

--upgrade-to=19.3.0
--upgrade-from=19
.2.0
Matteo Tassinari
quelle
Es beantwortet die Frage nicht, aber ein anderer Weg (in Bash, einer der Tags) ist my_script.sh "$(declare -p thearray)$". In myscript.sh lesen Sie es mit source /dev/stdin <<<"$1"Dann haben Sie thearrayin Ihrem Skript. Sie können neben dem Array auch andere Argumente verwenden. Sie können viele Variablen übergeben: my_script.sh "$(declare -p var1 var2 ...)"in diesem einzelnen Argument.
Dominic108

Antworten:

12

Mit einer Hilfsfunktion:

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

Der letzte Befehl im obigen Skript würde sich auf das Äquivalent des Schreibens erweitern

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

Die to_param_listFunktion verwendet den Namen einer Arrayvariablen und den Namen einer assoziativen Arrayvariablen und verwendet diese, um zwei "Namensreferenz" -Variablen in der Funktion zu erstellen (namerefs wurden in bashVersion 4.3 eingeführt). Diese werden dann verwendet, um die angegebene Array-Variable mit den Schlüsseln und Werten im entsprechenden Format aus dem assoziativen Array zu füllen.

Die Schleife in der Funktion durchläuft "${!inhash[@]}"die Liste der einzeln in Anführungszeichen gesetzten Schlüssel in Ihrem assoziativen Array.

Sobald der Funktionsaufruf zurückkehrt, verwendet das Skript das Array, um Ihr anderes Skript oder Ihren anderen Befehl aufzurufen.

Führen Sie die oben genannten mit

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

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

Das Skript würde ausgegeben

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

Dies zeigt, dass die Optionen generiert werden, ohne dass Wortteilung oder Dateinamen-Globbing wirksam werden. Es zeigt auch, dass die Reihenfolge der Schlüssel möglicherweise nicht beibehalten wird, da der Zugriff auf die Schlüssel aus einem assoziativen Array in einer ziemlich zufälligen Reihenfolge erfolgt.


Sie können eine Befehlssubstitution hier nicht wirklich sicher verwenden, da das Ergebnis eine einzelne Zeichenfolge wäre. Wenn diese Zeichenfolge nicht in Anführungszeichen gesetzt ist, wird sie (standardmäßig) in Leerzeichen aufgeteilt, wodurch zusätzlich sowohl die Schlüssel als auch die Werte Ihres assoziativen Arrays aufgeteilt werden. Die Shell würde auch Dateinamen-Globbing für die resultierenden Wörter ausführen. Das doppelte Zitieren der Befehlsersetzung würde nicht helfen, da dies dazu führen würde, dass Sie my_script.shmit einem einzigen Argument aufgerufen werden.


In Bezug auf Ihr Problem mitmakeself :

Das makeselfSkript führt dies mit den Argumenten für Ihr Installationsskript aus:

SCRIPTARGS="$*"

Dadurch werden die Argumente als Zeichenfolge $SCRIPTARGSgespeichert (verkettet, durch Leerzeichen getrennt). Dies wird später unverändert in das selbstextrahierende Archiv eingefügt. Für die Optionen richtig analysiert werden , wenn sie neu bewertet (was sie sind , wenn das Installationsprogramm ausgeführt wird ), erhalten Sie einen bereitstellen müssen , um zusätzlichen Satz von Anführungszeichen in den Werten der Parameter für sie richtig abgegrenzt werden.

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

Beachten Sie, dass dies kein Fehler in meinem Code ist. Es ist nur ein Nebeneffekt beim makeselfErstellen von Shell-Code basierend auf vom Benutzer angegebenen Werten.

Im Idealfall sollte das makeselfSkript jedes der bereitgestellten Argumente mit zusätzlichen Anführungszeichen versehen haben, dies ist jedoch nicht der Fall, da es schwierig ist zu wissen, welche Auswirkungen dies haben kann. Stattdessen überlässt es dem Benutzer, diese zusätzlichen Anführungszeichen bereitzustellen.

Wiederholen Sie meinen Test von oben, aber jetzt mit

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

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

produziert

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

Sie können sehen, dass diese Zeichenfolgen bei einer Neubewertung durch die Shell nicht auf Leerzeichen aufgeteilt werden.

Natürlich können Sie Ihr anfängliches assoziatives Array verwenden und stattdessen die Anführungszeichen in die to_param_listFunktion einfügen, indem Sie sie ändern

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

in

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

Jede dieser Änderungen an Ihrem Code würde die einfachen Anführungszeichen in den Werten der Optionen enthalten, sodass eine Neubewertung der Werte erforderlich würde .

Kusalananda
quelle
Ich habe Ihre Lösung ausprobiert. Wenn jedoch einer der Werte im assoziativen Startarray Leerzeichen enthält, wird der resultierende Befehl aufgelöst
Matteo Tassinari
@MatteoTassinari Nein, würde es nicht. Wenn dies der Fall ist, haben Sie die doppelten Anführungszeichen in "--$param=${inhash[$param]}"oder in vergessen "${list[@]}", oder das Skript, das die Optionen erhält, hat beim Parsen etwas falsch gemacht.
Kusalananda
Ich kann bestätigen , dass ich die Anführungszeichen verwendet , wie Sie angezeigt werden , diese Parameter übergeben werden github.com/megastep/makeself ein Installationsprogramm zu erstellen , die, wenn ausgeführt wird , ein Skript mit den gegebenen parametes aufruft, vielleicht an dieser Stelle etwas schief geht
Matteo Tassinari
1
Nein, das ist es nicht. Ich werde versuchen, meine Frage zu bearbeiten, um meinen Anwendungsfall besser darzustellen.
Matteo Tassinari
1
Ich fügte meinen tatsächlichen Anwendungsfall und den Fehler hinzu, den ich habe
Matteo Tassinari