JQ,两个查询,在json的不同部分,合并回来

Vet*_*tal 1 jq kubectl

我正在尝试使用 jq 提取 kubeconfig 数据。

kubectl config view --raw -o json | jq ...

有一个这样的json:

{
    "kind": "Config",
    "apiVersion": "v1",
    "preferences": {},
    "clusters": [
        {
            "name": "some-name",
            "cluster": {
                "server": "https://some-url",
                "certificate-authority-data": "some-cert"
            }
        },
      {
          "name": "another-name",
          "cluster": {
              "server": "https://another-url",
              "certificate-authority-data": "another-cert"
          }
      }
    ],
    "users": [
        {
            "name": "some-name",
            "user": {
                "username": "some-user",
                "password": "some-password"
            }
        },
        {
            "name": "another-name",
            "user": {
                "username": "another-user",
                "password": "another-password"
            }
        }
    ],
    "contexts": [],
    "current-context": "some-context"
}
Run Code Online (Sandbox Code Playgroud)

问题 1: 对于给定的名称,“some-name”,我想提取 json:

{
  url: "https://some-url",
  cert: "some-cert",
  username: "some-user",
  password: "some-password"
}
Run Code Online (Sandbox Code Playgroud)

问题#2: “用户”子部分可以有其他格式

"users": [
    {
        "name": "...",
        "user": {
            "exec": {
                ...
            }
Run Code Online (Sandbox Code Playgroud)

哪里.user.username.user.password两者都可能丢失

在这种情况下,整体查询应返回“{}”,即使“集群”查询/分支有结果


问题 3,作为 Jeff Mercado 回答的后续:

我想获得所有集群,加入(分组)名称:

查看手册,https://stedolan.github.io/jq/manual/#Builtinoperatorsandfunctions

“乘法、除法、取模:*、/ 和 %”部分,例如:

jq '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}' => {"k": {"a": 0, "b": 2, "c": 3}}'
Run Code Online (Sandbox Code Playgroud)

假设“k”是“name”的值,给出大概正确的结果。因此,按“k”分组,合并(*)结果。

我产生了以下查询:

echo "${json}" | jq -r  '(.clusters[] | {(.name): {url: .cluster.server, cert: .cluster["certificate-authority-data"]}}) * (.users[] | {(.name): {user: .user.username, password: .user.password}})'
Run Code Online (Sandbox Code Playgroud)

第一部分返回 {"name": {url: cert}},第二部分是 {"name": {username, password}} 但是,结果不是像 jq 手册中那样合并,而是其他东西......产品?

{
  "some-name": {
    "url": "https://some-url",
    "cert": "some-cert",
    "user": "some-user",
    "password": "some-password"
  }
}
{
  "another-name": {
    "url": "https://another-url",
    "cert": "another-cert"
  },
  "some-name": {
    "user": "some-user",
    "password": "some-password"
  }
}
{
  "some-name": {
    "url": "https://some-url",
    "cert": "some-cert"
  },
  "another-name": {
    "user": "another-user",
    "password": "another-password"
  }
}
{
  "another-name": {
    "url": "https://another-url",
    "cert": "another-cert",
    "user": "another-user",
    "password": "another-password"
  }
}

Run Code Online (Sandbox Code Playgroud)

为什么/是什么?有点像我(很可能是错误地)理解的产品('*')而不是 jq 教程的想法


实验: 我现在有 2 个查询产生部分结果。

让我们获取原始 json(上图)并解析:

read -d '' json << EOF
...
EOF
Run Code Online (Sandbox Code Playgroud)

查询:

echo "${json}" | jq -r '.clusters[] | select(.name=="some-name") | .cluster | {url: .server, cert: .["certificate-authority-data"]}' &&\
echo "${json}" | jq -r '.users[] | select(.name=="some-name") | .user | {user: .username, password: .password}'

Run Code Online (Sandbox Code Playgroud)

将产生拆分输出:

{
  "url": "https://some-url",
  "cert": "some-cert"
}
{
  "user": "some-user",
  "password": "some-password"
}

Run Code Online (Sandbox Code Playgroud)

或者,添加密钥以进行进一步合并:

echo "${json}" | jq -r '.clusters[] | select(.name=="some-name") | {name: .name, url: .cluster.server, cert: .cluster["certificate-authority-data"]}' &&\
echo "${json}" | jq -r '.users[] | select(.name=="some-name") | {name: .name, user: .user.username, password: .user.password}'
Run Code Online (Sandbox Code Playgroud)

将产生:


{
  "name": "some-name",
  "url": "https://some-url",
  "cert": "some-cert"
}
{
  "name": "some-name",
  "user": "some-user",
  "password": "some-password"
}

Run Code Online (Sandbox Code Playgroud)

"name" 不是必需的,但可以用作连接操作

Jef*_*ado 5

因此,您已经知道如何分别按名称获取集群和用户,第一步是在单个过滤器中同时选择它们:

(.clusters[] | select(.name == $name).cluster), (.users[] | select(.name == $name).user)
Run Code Online (Sandbox Code Playgroud)

这将产生两个独立的对象,集群,然后是用户。但我们想合并它们。有很多方法可以做到这一点。您可以+直接添加它们 ( ) 或合并它们 ( *) 但没有真正的区别。您只需要在需要的地方将属性重新映射到您想要的名称。

(.clusters[] | select(.name == $name).cluster | {url: .server, cert: ."certificate-authority-data"})
+
(.users[] | select(.name == $name).user | {username, password})
Run Code Online (Sandbox Code Playgroud)

将名称作为参数传递给您的过滤器;

$ kubectl config view --raw -o json | jq --arg name some-name '
(.clusters[] | select(.name == $name).cluster | {url: .server, cert: ."certificate-authority-data"})
+
(.users[] | select(.name == $name).user | {username, password})
'
Run Code Online (Sandbox Code Playgroud)

对于问题的第二部分,如果发现映射的用户缺少关键属性而您想省略它们,只需select在末尾添加另一个过滤器来测试这些属性,如果没有找到,则用空对象替换:

... | select(has("username") and has("password")) // {}
Run Code Online (Sandbox Code Playgroud)

jqplay