連想配列をパラメーターリストとしてスクリプトに渡す


9

スクリプトには、次のような連想配列があります。

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

それをフォームのパラメータリストに変換する単一のコマンドはありますか

--key1=value1 --key2=value2

手動で書き直す必要なし

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

私が考えていたユースケースは、次のように、パラメータのリストとして配列をスクリプトに渡すことでした。

my_script.sh $(to_param_list $VARS)

@Kusalanandaの回答で行ったコメントをさらに詳しく説明すると、私の正確な使用例は次のとおりです。makeselfを使用して自己解凍インストーラーをビルドするために使用するスクリプトがあり、このスクリプトは、次のように分離されるパラメーターを受け取ります。

  • スクリプト自体のパラメーター
  • 自己解凍インストーラー内のインストーラーのパラメーター

次に、スクリプトは次のようにインストーラーをビルドします。

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

ただし、パッケージ内の非常に単純なインストーラースクリプトを使用してパラメーターの受け渡しをテストしました。

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

次のような配列を渡します:

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

この出力結果:

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

質問には答えませんが、別の方法(bashではタグの1つ)はmy_script.sh "$(declare -p thearray)$"です。でmyscript.sh あなたとそれを読んでsource /dev/stdin <<<"$1"、あなたが持っているthearrayあなたのスクリプトで。配列と一緒に他の引数を持つことができます。多くの変数を渡すことができます:my_script.sh "$(declare -p var1 var2 ...)"この単一の引数で。
Dominic108

回答:


13

ヘルパー関数で:

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

上記のスクリプトの最後のコマンドは、

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

このto_param_list関数は、配列変数の名前と連想配列変数の名前を取り、これらを使用して関数に2つの「名前参照」変数を作成します(namerefはリリース4.3で導入されました)。次に、これらを使用して、指定した配列変数に、連想配列から適切な形式のキーと値を設定します。bash

関数のループはを反復します"${!inhash[@]}"。これは、連想配列で個別に引用されたキーのリストです。

関数呼び出しが戻ると、スクリプトは配列を使用して他のスクリプトまたはコマンドを呼び出します。

上記を実行する

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

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

スクリプトは出力します

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

これは、単語分割やファイル名グロビングが有効にならないでオプションが生成されることを示しています。また、連想配列からキーにアクセスするとかなりランダムな順序でキーがアクセスされるため、キーの順序が保持されない可能性があることも示しています。


結果として単一の文字列になるため、ここでは実際にコマンド置換を安全に使用することはできません。引用符で囲まれていない場合、この文字列は空白文字(デフォルト)で分割され、連想配列のキーと値の両方がさらに分割されます。シェルはまた、結果の単語に対してファイル名のグロビングを実行します。コマンド置換を二重引用符で囲んmy_script.shでも、1つの引数でyourが呼び出されるため、役に立ちません。


の問題についてmakeself

makeselfこのスクリプトは、あなたのインストーラスクリプトに引数を指定して、この処理を行います。

SCRIPTARGS="$*"

これにより、引数が$SCRIPTARGS(連結され、スペースで区切られた)文字列として保存されます。これは後で自己解凍アーカイブにそのまま挿入されます。オプションが再評価されたときに(インストーラーの実行時に)オプションが正しく解析されるようにするには、パラメーターの値に追加の引用符のセットを提供して、それらを正しく区切る必要があります。

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

これは私のコードのバグではないことに注意してください。これは、ユーザーが指定した値に基づいてシェルコードmakeself生成することの副作用にすぎません。

理想的には、makeselfスクリプトは、提供された各引数を引用符で囲む必要がありますが、そうではない可能性があります。代わりに、これらの追加の引用を提供するのはユーザーに任されます。

上からテストを再実行しますが、

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

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

作り出す

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

これらの文字列は、シェルによって再評価されたときに、スペースで分割されないことがわかります。

もちろん、最初の連想配列を使用して、代わりにto_param_list関数に引用符を追加して、

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

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

コードへのこれらの変更はどちらも、オプションの値に単一引用符を含めるため、値の再評価が必要になります。


私はあなたの解決策を試しましたが、最初の連想配列のいずれかの値にスペースが含まれている場合、結果のコマンドは壊れます
Matteo Tassinari

@MatteoTassinariいいえ、そうではありません。含まれている場合は、"--$param=${inhash[$param]}"またはで二重引用符を忘れたか"${list[@]}"、オプションを受け取るスクリプトがそれらを解析する際に何らかの問題を起こしています。
クサラナンダ

私はあなたが表示されているように私には引用符を使用していることを確認することができ、これらのパラメータが渡されgithub.com/megastep/makeselfおそらく、この通路に何かがうまくいかない、実行は、与えられたparametesでスクリプトを呼び出し、インストーラを作成するために
マッテオ・タシナリ

1
いいえ、それはそうではありません。私のユースケースをよりよく示すために質問を編集しようとします。
Matteo Tassinari

1
私は実際のユースケースと私が持っているエラーを追加しました
Matteo Tassinari
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.