Passe o array associativo como lista de parâmetros para o script


9

Em um script, tenho uma matriz associativa como:

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

Existe um único comando para transformar isso em uma lista de parâmetros no formulário

--key1=value1 --key2=value2

sem ter que reescrever manualmente

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

o caso de uso que eu tinha em mente era passar a matriz para um script como uma lista de parâmetros, como

my_script.sh $(to_param_list $VARS)

Para expandir o comentário que fiz na resposta do @Kusalananda, meu caso de uso exato é o seguinte: Eu tenho um script que é usado para criar um instalador de extração automática usando o makeelf, e esse script recebe alguns parâmetros que devem ser separados entre:

  • parâmetros para o próprio script
  • parâmetros para o instalador dentro do instalador de extração automática

Os scripts criam o instalador da seguinte maneira:

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

No entanto, testei o parâmetro passando com um script de instalação muito simples dentro do pacote:

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

e passando uma matriz como:

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

resulta nesta saída:

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

Ele não responde à pergunta, mas outra maneira (no bash, uma das tags) é my_script.sh "$(declare -p thearray)$". Em myscript.sh você lê com source /dev/stdin <<<"$1"Então você tem thearrayem seu script. Você pode ter outros argumentos ao lado da matriz. Você pode passar muitas variáveis: my_script.sh "$(declare -p var1 var2 ...)"neste único argumento.
— Dominic108

Respostas:


13

Com uma função 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[@]}"

O comando final no script acima seria expandido para o equivalente a ter escrito

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

A to_param_listfunção pega o nome de uma variável de matriz e o nome de uma variável de matriz associativa e os utiliza para criar duas variáveis ​​de "referência de nome" na função (os namerefs foram introduzidos na bashliberação 4.3). Eles são usados ​​para preencher a variável de matriz fornecida com as chaves e os valores no formato apropriado da matriz associativa.

O loop na função repete "${!inhash[@]}", que é a lista de chaves citadas individualmente em sua matriz associativa.

Quando a chamada de função retornar, o script usaria a matriz para chamar seu outro script ou comando.

Executando o acima com

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

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

o script sairia

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

Isso mostra que as opções são geradas sem que a divisão de palavras ou o globbing do nome do arquivo entrem em vigor. Também mostra que a ordem das chaves pode não ser preservada, pois o acesso às chaves a partir de uma matriz associativa o fará em uma ordem bastante aleatória.


Você não pode realmente usar uma substituição de comando com segurança aqui, pois o resultado seria uma única string. Se não estiver entre aspas, essa sequência será dividida em caracteres de espaço em branco (por padrão), que dividiriam adicionalmente as chaves e os valores de sua matriz associativa. O shell também executaria um globbing de nome de arquivo nas palavras resultantes. Citar duas vezes a substituição de comando não ajudaria, pois isso resultaria em chamar seu my_script.shcom um único argumento.


Em relação ao seu problema commakeself :

O makeselfscript faz isso com os argumentos do script do instalador:

SCRIPTARGS="$*"

Isso salva os argumentos como uma sequência $SCRIPTARGS(concatenada, separada por espaços). Posteriormente, ele é inserido no arquivo de extração automática como está. Para que as opções sejam analisadas corretamente quando são reavaliadas (que são ao executar o instalador), você precisará fornecer um conjunto extra de cotações nos valores dos parâmetros para que sejam delimitados corretamente.

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

Observe que isso não é um bug no meu código. É apenas um efeito colateral da makeselfprodução de código shell com base nos valores fornecidos pelo usuário.

Idealmente, o makeselfscript deve ter escrito cada um dos argumentos fornecidos com um conjunto extra de aspas, mas não é presumível, porque é difícil saber qual efeito isso pode ter. Em vez disso, deixa ao usuário fornecer essas cotações extras.

Reexecutando meu teste de cima, mas agora com

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

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

produz

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

Você pode ver que essas cadeias, quando reavaliadas pelo shell, não seriam divididas em espaços.

Obviamente, você pode usar sua matriz associativa inicial e adicionar as aspas na to_param_listfunção alterando

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

para dentro

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

Uma dessas alterações no seu código incluiria aspas simples nos valores das opções, portanto, uma reavaliação dos valores seria necessária .


Eu tentei sua solução, no entanto, se um dos valores na matriz associativa começando contém qualquer espaço, o comando resultante vai quebrar
— Matteo Tassinari

@MatteoTassinari Não, não seria. Se isso acontecer, você esqueceu as aspas duplas em "--$param=${inhash[$param]}"ou dentro "${list[@]}", ou o script que recebe as opções faz algo errado ao analisá-las.
— Kusalananda

Posso confirmar que usei as aspas como você está mostrando, esses parâmetros são passados ​​para github.com/megastep/makeself para criar um instalador que, quando executado, invoca um script com os parâmetros especificados, talvez nesta passagem algo dê errado
— Matteo Tassinari

11
Não, não, tentarei editar minha pergunta para mostrar melhor meu caso de uso.
— Matteo Tassinari

11
Eu adicionei meu caso de uso real e o erro que estou tendo #
— Matteo Tassinari
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.