我知道关于如何从关联数组创建 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
一种可能的解决方案是:
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
$n
aliases
reduce
paths
$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
,因此我们对数组的键施加了一些明显的限制(可能不包含=
等[]
)
我们可以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
或其他适当的编程语言而不是 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})'