joを使用してシェルの連想配列からJSONオブジェクトを作成するには?

joを使用してシェルの連想配列からJSONオブジェクトを作成するには?

私は知っています連想配列からJSONを生成する方法しかし、それは私の問題ではありません。

次の連想配列があります。

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

この連想配列を次のJSONに変換する必要があります。

{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "Index": ["components/Index/Exports"],
            "Shared": ["components/Shared/Exports"],
            "Icons": ["components/Icons/Exports"],
        }
    }
}

joとを使用したいjq。しかし、ネストがわかりません。

私はこのコードを試しました:

jo -p compilerOptions[baseUrl]=. compilerOptions[paths]="$(jo -p a ${Aliases[@]})"

しかし、実行すらされません。

答え1

考えられる解決策の1つは次のとおりです。

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

jq -n --argjson n "${#aliases[@]}" '
        { compileroption: {
                baseurl: ".",
                paths:
                (
                        reduce range($n) as $i ({};
                                .[$ARGS.positional[$i]] = [$ARGS.positional[$i+$n]]
                        )
                )
        } }' --args "${!aliases[@]}" "${aliases[@]}"

jo連想配列を使用する代わりに、キーと値はコマンドの最後に位置引数aliasesとして渡されます(使用される場合は常に最後のオプションでなければなりません)。ユーティリティはキーと値を単一の配列として受け取ります。つまり、配列の最初の半分にキーが含まれ、配列の2番目の半分に対応する値が含まれます。jq--args--argsjq$ARGS.positional

式の本文は、jq出力オブジェクトを生成し、reduceゼロから始まる整数範囲で機能します。ここでは、配列の要素数です。この操作では、 :th パラメーターをキーとして使用し、 + :th パラメーターをその配列値の要素として使用して、位置パラメーターを 1 つずつ追加してオブジェクトを作成します。$n$naliasesreducepaths$i$i$n


jo連想配列の各キーと値のペアに対してリーフオブジェクトを作成する方法は少し異なります。

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

for key in "${!aliases[@]}"; do
        jo "$key[]=${aliases[$key]}"
done

これにより、3つのオブジェクトが出力されます。

{"Icons":["components/Icons/Exports"]}
{"Index":["components/Index/Exports"]}
{"Shared":["components/Shared/Exports"]}

私たちはこれをこのように使用しているので、jo配列のキーにいくつかの明白な制限を適用します(=などを含めない場合があります[])。

私たちはこれを次jqのように使用できますjo

for key in "${!aliases[@]}"; do
        jq -n --arg key "$key" --arg value "${aliases[$key]}" '.[$key] = [$value]'
done

その後、それを読み取り、作成中のオブジェクトの正しい場所に追加できますjq

declare -A aliases
aliases[Index]=components/Index/Exports
aliases[Shared]=components/Shared/Exports
aliases[Icons]=components/Icons/Exports

for key in "${!aliases[@]}"; do
        jo "$key[]=${aliases[$key]}"
done |
jq -n '{ compileroptions: {
        baseURL: ".",
        paths: (reduce inputs as $item ({}; . += $item)) } }'

ここでの主な違いは、jqコンテンツをコマンドラインオプションとして渡すのではなく、JSONオブジェクトストリームに渡すことです。

答え2

perl個人的には、私はシェル(特にbash!)の代わりに他の適切なプログラミング言語を使います。または、少なくともzshより良い連想配列のサポートに切り替えて、perlJSONy操作を実行するために使用してください。

#! /usr/bin/perl
use JSON;

%my_aliases = (qw(
  Index   components/Index/Exports
  Shared  components/Shared/Exports
  Icons   components/Icons/Exports
));

$j->{compilerOptions}->{baseUrl} = "";
$j->{compilerOptions}->{paths}->{$_} = [$my_aliases{$_}] for keys%my_aliases;
print to_json($j, {"pretty" => 1});

または:

#! /bin/zsh -

typeset -A my_aliases=(
  Index   components/Index/Exports
  Shared  components/Shared/Exports
  Icons   components/Icons/Exports
)

print -rNC1 -- "${(kv@)my_aliases}" |
  perl -MJSON -0e '
    chomp (@records = <>);
    %my_aliases = @records;
    $j->{compilerOptions}->{baseUrl} = "";
    $j->{compilerOptions}->{paths}->{$_} = [$my_aliases{$_}] for keys%my_aliases;
    print to_json($j, {"pretty" => 1})'

関連情報