如何使用 jo 从 shell 中的关联数组创建 JSON 对象?

如何使用 jo 从 shell 中的关联数组创建 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"],
        }
    }
}

我想使用jojq。但我无法想出嵌套。

我尝试了这段代码:

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

但它甚至不运行。

答案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作为jq位置参数传递--args到命令末尾的 with (--args必须始终是最后一个选项,如果使用的话)。该jq实用程序将键和值作为单个数组接收$ARGS.positional。这意味着数组的前半部分包含键,数组的后半部分包含相应的值。

表达式的主体jq创建输出对象,并对从零开始的reduce一系列整数进行运算,其中是数组中元素的数量。该操作通过一一添加位置参数来构建对象,使用:th 参数作为键,+ :th 参数作为相应数组值中的元素。$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

这将输出三个对象

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

由于我们这样使用jo,因此我们对数组的键施加了一些明显的限制(可能不包含=[]

我们可以jqjo这样使用:

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或其他适当的编程语言而不是 shell(尤其是 bash!)。或者至少切换到zsh更好的关联数组支持并用于perl执行 JSONy 操作:

#! /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})'

相关内容