从 bash 变量和关联数组创建 json
create json from bash variable and associative array
假设我在 bash 中声明了以下内容:
mcD="had_a_farm"
eei="eeieeio"
declare -A animals=( ["duck"]="quack_quack" ["cow"]="moo_moo" ["pig"]="oink_oink" )
我想要以下 json:
{
"oldMcD": "had a farm",
"eei": "eeieeio",
"onThisFarm":[
{
"duck": "quack_quack",
"cow": "moo_moo",
"pig": "oink_oink"
}
]
}
现在我知道我可以使用 echo、printf 或将文本分配给变量来完成此操作,但让我们假设 animals
实际上非常大,这样做会很麻烦。我还可以循环遍历我的变量和关联数组,并在这样做时创建一个变量。我可以编写这些解决方案中的任何一个,但两者看起来都像是 “错误的方式”。更不用说处理 animals
中的最后一项令人讨厌了,之后我不想要一个“,”。
我认为正确的解决方案是使用 jq,但我很难找到很多关于如何使用此工具编写 jsons(尤其是嵌套的)的文档和示例而不是解析它们。
这是我想出的:
jq -n --arg mcD "$mcD" --arg eei "$eei" --arg duck "${animals['duck']}" --arg cow "${animals['cow']}" --arg pig "${animals['pig']}" '{onThisFarm:[ { pig: $pig, cow: $cow, duck: $duck } ], eei: $eei, oldMcD: $mcD }'
生成所需的结果。实际上,我并不真正关心 json 中键的顺序,但 jq 的输入必须倒退才能按所需顺序获得它,这仍然很烦人。无论如何,这个解决方案很笨重,而且并不比简单地声明一个看起来像 json 的字符串变量更容易编写(并且对于更大的关联数组是不可能的)。如何以高效、合乎逻辑的方式构建这样的 json?
谢谢!
您可以使用 for 循环减少关联数组并将其通过管道传递给 jq
:
for i in "${!animals[@]}"; do
echo "$i"
echo "${animals[$i]}"
done |
jq -n -R --arg mcD "$mcD" --arg eei "$eei" 'reduce inputs as $i ({onThisFarm: [], mcD: $mcD, eei: $eei}; .onThisFarm[0] += {($i): (input | tonumber ? // .)})'
假设“animals”数组中的none个键或值包含换行符:
for i in "${!animals[@]}"
do
printf "%s\n%s\n" "${i}" "${animals[$i]}"
done | jq -nR --arg oldMcD "$mcD" --arg eei "$eei" '
def to_o:
. as $in
| reduce range(0;length;2) as $i ({};
.[$in[$i]]= $in[$i+1]);
{$oldMcD,
$eei,
onthisfarm: [inputs] | to_o}
'
注意 {$x}
实际上扩展为 {(x): $x}
的技巧
使用“\u0000”作为分隔符
如果任何键或值包含换行符,您可以调整上面的内容,以便使用“\u0000”作为分隔符:
for i in "${!animals[@]}"
do
printf "%s[=11=]%s[=11=]" "${i}" "${animals[$i]}"
done | jq -sR --arg oldMcD "$mcD" --arg eei "$eei" '
def to_o:
. as $in
| reduce range(0;length;2) as $i ({};
.[$in[$i]]= $in[$i+1]);
{$oldMcD,
$eei,
onthisfarm: split("\u0000") | to_o }
'
注:以上假设jq版本为1.5以上
假设我在 bash 中声明了以下内容:
mcD="had_a_farm"
eei="eeieeio"
declare -A animals=( ["duck"]="quack_quack" ["cow"]="moo_moo" ["pig"]="oink_oink" )
我想要以下 json:
{
"oldMcD": "had a farm",
"eei": "eeieeio",
"onThisFarm":[
{
"duck": "quack_quack",
"cow": "moo_moo",
"pig": "oink_oink"
}
]
}
现在我知道我可以使用 echo、printf 或将文本分配给变量来完成此操作,但让我们假设 animals
实际上非常大,这样做会很麻烦。我还可以循环遍历我的变量和关联数组,并在这样做时创建一个变量。我可以编写这些解决方案中的任何一个,但两者看起来都像是 “错误的方式”。更不用说处理 animals
中的最后一项令人讨厌了,之后我不想要一个“,”。
我认为正确的解决方案是使用 jq,但我很难找到很多关于如何使用此工具编写 jsons(尤其是嵌套的)的文档和示例而不是解析它们。
这是我想出的:
jq -n --arg mcD "$mcD" --arg eei "$eei" --arg duck "${animals['duck']}" --arg cow "${animals['cow']}" --arg pig "${animals['pig']}" '{onThisFarm:[ { pig: $pig, cow: $cow, duck: $duck } ], eei: $eei, oldMcD: $mcD }'
生成所需的结果。实际上,我并不真正关心 json 中键的顺序,但 jq 的输入必须倒退才能按所需顺序获得它,这仍然很烦人。无论如何,这个解决方案很笨重,而且并不比简单地声明一个看起来像 json 的字符串变量更容易编写(并且对于更大的关联数组是不可能的)。如何以高效、合乎逻辑的方式构建这样的 json?
谢谢!
您可以使用 for 循环减少关联数组并将其通过管道传递给 jq
:
for i in "${!animals[@]}"; do
echo "$i"
echo "${animals[$i]}"
done |
jq -n -R --arg mcD "$mcD" --arg eei "$eei" 'reduce inputs as $i ({onThisFarm: [], mcD: $mcD, eei: $eei}; .onThisFarm[0] += {($i): (input | tonumber ? // .)})'
假设“animals”数组中的none个键或值包含换行符:
for i in "${!animals[@]}"
do
printf "%s\n%s\n" "${i}" "${animals[$i]}"
done | jq -nR --arg oldMcD "$mcD" --arg eei "$eei" '
def to_o:
. as $in
| reduce range(0;length;2) as $i ({};
.[$in[$i]]= $in[$i+1]);
{$oldMcD,
$eei,
onthisfarm: [inputs] | to_o}
'
注意 {$x}
实际上扩展为 {(x): $x}
使用“\u0000”作为分隔符
如果任何键或值包含换行符,您可以调整上面的内容,以便使用“\u0000”作为分隔符:
for i in "${!animals[@]}"
do
printf "%s[=11=]%s[=11=]" "${i}" "${animals[$i]}"
done | jq -sR --arg oldMcD "$mcD" --arg eei "$eei" '
def to_o:
. as $in
| reduce range(0;length;2) as $i ({};
.[$in[$i]]= $in[$i+1]);
{$oldMcD,
$eei,
onthisfarm: split("\u0000") | to_o }
'
注:以上假设jq版本为1.5以上