我想将bash中的关联数组转换为json hash / dict。我宁愿使用jq来执行此操作,因为它已经是一个依赖项,并且我可以依靠它来生成格式良好的json。有人可以演示如何实现这一目标吗?
#!/bin/bash declare -A dict=() dict["foo"]=1 dict["bar"]=2 dict["baz"]=3 for i in "${!dict[@]}" do echo "key : $i" echo "value: ${dict[$i]}" done echo 'desired output using jq: { "foo": 1, "bar": 2, "baz": 3 }'
有很多可能性,但是鉴于您已经编写了一个bash for循环,您可能希望从脚本的这种变体开始:
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实体。在当前情况下,我们可以这样写:
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? // .)。
fromjson? // .
这是jq常见问题解答中提到并由@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 } }