有很多可能性,但鉴于您已经编写了一个 bash for 循环,您可能希望从脚本的这个变体开始:
#!/bin/bash
# Requires bash with associative arrays
declare -A dict
dict["foo"]=1
dict["bar"]=2
dict["baz"]=3
for i in "${!dict[@]}"
do
echo "$i"
echo "${dict[$i]}"
done |
jq -n -R 'reduce inputs as $i ({}; . + { ($i): (input|(tonumber? // .)) })'
结果反映了 bash for 循环产生的键的顺序:
{
"bar": 2,
"baz": 3,
"foo": 1
}
一般来说,基于为 jq 提供键值对的方法,即一行中的一个键和下一行中的相应值,有很多值得推荐的地方。下面给出了一个遵循这个通用方案但使用 NUL 作为“行尾”字符的通用解决方案。
作为 JSON 实体的键和值
为了使上述内容更通用,最好将键和值呈现为 JSON 实体。在本例中,我们可以这样写:
for i in "${!dict[@]}"
do
echo "\"$i\""
echo "${dict[$i]}"
done |
jq -n 'reduce inputs as $i ({}; . + { ($i): input })'
其他变体
JSON 键必须是 JSON 字符串,因此可能需要一些工作来确保实现从 bash 键到 JSON 键的所需映射。类似的说明适用于从 bash 数组值到 JSON 值的映射。处理任意 bash 键的一种方法是让 jq 进行转换:
printf "%s" "$i" | jq -Rs .
您当然可以对 bash 数组值做同样的事情,并让 jq 检查该值是否可以根据需要转换为数字或其他 JSON 类型(例如,使用 fromjson? // .)。
通用解决方案
这是一个通用的解决方案,类似于 jq FAQ 中提到的并由@CharlesDuffy 提倡。它在将 bash 键和值传递给 jq 时使用 NUL 作为分隔符,并且具有只需要一次调用 jq 的优点。如果需要,过滤器fromjson? // . 可以省略或替换为另一个过滤器。
declare -A dict=( [$'foo\naha']=$'a\nb' [bar]=2 [baz]=$'{"x":0}' )
for key in "${!dict[@]}"; do
printf '%s\0%s\0' "$key" "${dict[$key]}"
done |
jq -Rs '
split("\u0000")
| . as $a
| reduce range(0; length/2) as $i
({}; . + {($a[2*$i]): ($a[2*$i + 1]|fromjson? // .)})'
输出:
{
"foo\naha": "a\nb",
"bar": 2,
"baz": {
"x": 0
}
}