从bash关联数组构造json哈希 [英] Constructing a json hash from a bash associative array

查看:80
本文介绍了从bash关联数组构造json哈希的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将bash中的关联数组转换为json哈希/字典.我宁愿使用jq来执行此操作,因为它已经是一个依赖项,并且我可以依靠它来生成格式正确的json.有人可以演示如何实现这一目标吗?

I would like to convert an associative array in bash to a json hash/dict. I would prefer to use jq to do this as it is already a dependency and I can rely on it to produce well formed json. Could someone demonstrate how to achieve this?

#!/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循环,您可能希望从脚本的这种变体开始:

There are many possibilities, but given that you already have written a bash for loop, you might like to begin with this variation of your script:

#!/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循环产生的键的顺序:

The result reflects the ordering of keys produced by the bash for loop:

{
  "bar": 2,
  "baz": 3,
  "foo": 1
}

通常,基于馈送jq键值对的方法有很多值得推荐的方法,其中一个键在一行上,然后是对应的值在下一行上.下面给出了遵循此通用方案但使用NUL作为行尾"字符的通用解决方案.

In general, the approach based on feeding jq the key-value pairs, with one key on a line followed by the corresponding value on the next line, has much to recommend it. A generic solution following this general scheme, but using NUL as the "line-end" character, is given below.

要使以上内容更为通用,最好将键和值显示为JSON实体.在当前情况下,我们可以这样写:

To make the above more generic, it would be better to present the keys and values as JSON entities. In the present case, we could write:

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进行转换:

Other Variations

JSON keys must be JSON strings, so it may take some work to ensure that the desired mapping from bash keys to JSON keys is implemented. Similar remarks apply to the mapping from bash array values to JSON values. One way to handle arbitrary bash keys would be to let jq do the conversion:

printf "%s" "$i" | jq -Rs .

您当然可以对bash数组值做同样的事情,让jq检查该值是否可以根据需要转换为数字或其他JSON类型(例如,使用fromjson? // .).

You could of course do the same thing with the bash array values, and let jq check whether the value can be converted to a number or to some other JSON type as desired (e.g. using fromjson? // .).

这是jq常见问题解答中提到并由@CharlesDuffy倡导的通用解决方案.在将bash键和值传递给jq时,它将NUL用作定界符,并且具有只需要对jq进行一次调用的优点.如果需要,可以省略过滤器fromjson? // .或将其替换为另一个过滤器.

Here is a generic solution along the lines mentioned in the jq FAQ and advocated by @CharlesDuffy. It uses NUL as the delimiter when passing the bash keys and values to jq, and has the advantage of only requiring one call to jq. If desired, the filter fromjson? // . can be omitted or replaced by another one.

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
  }
}

这篇关于从bash关联数组构造json哈希的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆