Passa l'array associativo come elenco di parametri allo script


9

In uno script ho una matrice associativa come:

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

Esiste un singolo comando per trasformarlo in un elenco di parametri nel modulo

--key1=value1 --key2=value2

senza dover riscrivere manualmente

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

il caso d'uso che avevo in mente era di passare l'array a uno script come un elenco di parametri, come

my_script.sh $(to_param_list $VARS)

Per espandere il commento che ho fatto sulla risposta di @Kusalananda, il mio caso d'uso esatto è il seguente: ho uno script che viene utilizzato per creare un programma di installazione autoestraente usando makeelf, e questo script riceve alcuni parametri che devono essere separati tra:

  • parametri per lo script stesso
  • parametri per il programma di installazione all'interno del programma di installazione autoestraente

Gli script costruiscono quindi il programma di installazione in questo modo:

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

Tuttavia, ho testato il parametro passando con uno script di installazione molto semplice all'interno del pacchetto:

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

e passando un array come:

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

risulta in questo output:

--upgrade-to=19.3.0
--upgrade-from=19
.2.0

Non risponde alla domanda, ma un altro modo (in bash, uno dei tag) è my_script.sh "$(declare -p thearray)$". In myscript.sh tu lo leggi con source /dev/stdin <<<"$1"Poi hai thearraynella tua sceneggiatura. Puoi avere altri argomenti a fianco dell'array. Puoi passare molte variabili: my_script.sh "$(declare -p var1 var2 ...)"in questo singolo argomento.
Dominic108,

Risposte:


13

Con una funzione di aiuto:

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

Il comando finale nello script sopra si espanderebbe all'equivalente di aver scritto

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

La to_param_listfunzione prende il nome di una variabile di array e il nome di una variabile di array associativo e li usa per creare due variabili di "riferimento al nome" nella funzione (sono state introdotte namerefs nella bashversione 4.3). Questi vengono quindi utilizzati per popolare la variabile matrice fornita con le chiavi e i valori nel formato appropriato dalla matrice associativa.

Il ciclo nella funzione scorre ripetutamente "${!inhash[@]}", che è l'elenco delle chiavi citate individualmente nell'array associativo.

Una volta restituita la chiamata di funzione, lo script utilizza l'array per chiamare l'altro script o comando.

Eseguendo quanto sopra con

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

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

lo script verrebbe prodotto

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

Questo dimostra che le opzioni sono generate senza dividere le parole o rendere effettivi i globbing del nome file. Mostra anche che l'ordine delle chiavi potrebbe non essere preservato poiché l'accesso alle chiavi da un array associativo lo farà in un ordine abbastanza casuale.


Non è possibile utilizzare una sostituzione di comando in modo sicuro qui poiché il risultato sarebbe una singola stringa. Se non quotato, questa stringa verrebbe quindi suddivisa su caratteri di spazi bianchi (per impostazione predefinita), che dividerebbe ulteriormente sia le chiavi che i valori dell'array associativo. La shell eseguirà anche il globbing del nome file sulle parole risultanti. La doppia citazione della sostituzione del comando non sarebbe di aiuto in quanto ciò comporterebbe la chiamata my_script.shcon un singolo argomento.


Per quanto riguarda il tuo problema conmakeself :

Lo makeselfscript fa questo con gli argomenti dello script del programma di installazione:

SCRIPTARGS="$*"

Questo salva gli argomenti come una stringa in $SCRIPTARGS(concatenati, separati da spazi). Successivamente viene inserito così com'è nell'archivio autoestraente. Affinché le opzioni vengano analizzate correttamente quando vengono rivalutate (come lo sono quando si esegue il programma di installazione), sarà necessario fornire una serie aggiuntiva di virgolette nei valori dei parametri per poter essere correttamente delimitate.

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

Nota che questo non è un bug nel mio codice. È solo un effetto collaterale della makeselfproduzione di codice shell basato sui valori forniti dall'utente.

Idealmente, lo makeselfscript avrebbe dovuto scrivere ciascuno degli argomenti forniti con un set aggiuntivo di virgolette attorno a loro, ma non lo è, presumibilmente perché è difficile sapere quale effetto potrebbe avere. Al contrario, lascia all'utente la possibilità di fornire questi preventivi aggiuntivi.

Rieseguendo il mio test dall'alto, ma ora 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'

Si può vedere che queste stringhe, se rivalutate dalla shell, non verrebbero divise sugli spazi.

Ovviamente, potresti usare il tuo array associativo iniziale e invece aggiungere le virgolette nella to_param_listfunzione cambiando

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

in

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

Ognuna di queste modifiche al codice includerebbe le virgolette singole nei valori delle opzioni, quindi sarebbe necessaria una rivalutazione dei valori .


Ho provato la tua soluzione, tuttavia se uno dei valori nella matrice associativa iniziale contiene dello spazio, il comando risultante verrà interrotto
Matteo Tassinari

@MatteoTassinari No, non lo sarebbe. In questo caso, hai dimenticato le doppie virgolette dentro "--$param=${inhash[$param]}"o dentro "${list[@]}", oppure lo script che riceve le opzioni fa qualcosa di sbagliato nell'analizzarle.
Kusalananda

Posso confermare che ho usato le virgolette come stai mostrando, questi parametri vengono passati a github.com/megastep/makeself per creare un programma di installazione che, quando viene eseguito, invoca uno script con i parametri impostati, forse in questo passaggio qualcosa va storto
Matteo Tassinari,

1
No, non è quello, proverò a modificare la mia domanda per mostrare meglio il mio caso d'uso.
Matteo Tassinari,

1
Ho aggiunto il mio caso d'uso reale e l'errore che sto riscontrando
Matteo Tassinari il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.