使用jq将x = y对转换为键/值对

时间:2017-05-02 03:32:48

标签: json parsing key environment-variables jq

我试图从docker inspect的JSON输出中解析环境变量。令人讨厌的是,这些环境变量不作为有用的键值对返回。它们只是一个x = y字符串的数组。这是输出的相关片段:

[
    {
        "Config": {
            "Env": [
                "JENKINS_HOST=1.2.3.4",
                "JENKINS_INSTANCE=tea",
                "JENKINS_NAME=Enterprise Architecture Tools",
                "JENKINS_VERSION=2.46.2",
                "JENKINS_PROTOCOL=http"
            ]
        }
    }
]

我想把这个数组转换成这样的东西:

{
  "Config": {
    "Env": {
      "JENKINS_HOST": "1.2.3.4",
      "JENKINS_INSTANCE": "tea",
      "JENKINS_NAME": "Enterprise Architecture Tools",
      "JENKINS_VERSION": "2.46.2",
      "JENKINS_PROTOCOL": "http"
    }
  }
}

这样,我可以使用像jq '.[] | .Config.Env.JENKINS_HOST'这样的命令来获取我关心的值。我无法弄清楚如何实现这一目标。

选择数据相对容易,甚至将键和值拆分为单独的元素。例如,如果我使用jq '.[] | .Config.Env | .[] | split("=")',我会得到这样的数据:

[
  "JENKINS_HOST",
  "1.2.3.4"
]
[
  "JENKINS_INSTANCE",
  "tea"
]
[
  "JENKINS_NAME",
  "Enterprise Architecture Tools"
]
[
  "JENKINS_VERSION",
  "2.46.2"
]
[
  "JENKINS_PROTOCOL",
  "http"
]

但是,我无法弄清楚如何将该数据转换为对象分配。它似乎应该是mapreduce的某种组合,但我很难过。有人能指出我正确的方向吗?

2 个答案:

答案 0 :(得分:8)

要将两个字符串的数组(例如[" k"," v"])转换为对象,您可以写:

{ (.[0]) : .[1] }

所以你想要写一些类似的东西:

 map(.Config.Env |= (map( split("=") | { (.[0]) : .[1] } ) | add))

A2O

抽象出数组到对象的功能使解决方案更容易消化:

def a2o: map( split("=") | { (.[0]) : .[1] } ) | add;

map(.Config.Env |= a2o)

使用matchcapture代替split

因为" ="字符出现在"值"每个var=value字符串的一部分,天真地使用split可能不是一个好主意。假设您的jq支持正则表达式,这是一个更强大的替代方法:

match("([^=]*)=(.*)") | .captures | {(.[0].string) : .[1].string}

或者,更简洁,也许更优雅:

[capture( "(?<key>[^:]*):(?<value>.*)" )] | from_entries

index/1

如果您的jq没有正则表达式支持,您可以使用index/1,这些行:

index("=") as $ix | {(.[:$ix]) : .[$ix+1:]}

答案 1 :(得分:0)

给定要转换为单个对象的项目集合,我通常会选择使用reduce来实现此目的。将这些项目变成其组成键和值,然后分配给结果对象。

reduce (.[] | split("=")) as [$key, $value] ({}; .[$key] = $value)

虽然在这里也使用from_entries也很有用,但您可以创建它期望的键/值对象的数组。

map(split("=") as [$key, $value] | {$key, $value}) | from_entries

然后使用您选择的任何一种方法将所有这些与Env属性的更新放在一起。

.[].Config.Env |= reduce (.[] | split("=")) as [$key, $value] ({}; .[$key] = $value)
#or
.[].Config.Env |= (map(split("=") as [$key, $value] | {$key, $value}) | from_entries)

https://jqplay.org/s/qfItW5U-Tf