如何使用 jq 搜索 json 的值?

How to search a json with jq for values?

我有一个json这种结构:

{
  "nodes": {
    "60e327ee58a0": {
      "nodeinfo": {
        "network": {
          "mesh": {
            "bat0": {
              "interfaces": {
                "wireless": [
                  "<mac-address-removed>"
                ],
                "tunnel": [
                  "<mac-address-removed>"
                ]
              }
            }
          },
          "mac": "<mac removed>",
          "addresses": [
            "<ipv6 removed>",
            "<ipv6 removed>"
          ]
        },
        "hardware": {
          "model": "TP-Link TL-WR841N/ND v10",
          "nproc": 1
        },
        "software": {
          "batman-adv": {
            "compat": 15,
            "version": "2015.1"
          },
          "autoupdater": {
            "branch": "stable",
            "enabled": true
          },
          "firmware": {
            "release": "v2016.1+1.0.1",
            "base": "gluon-v2016.1"
          },
          "status-page": {
            "api": 1
          },
          "fastd": {
            "enabled": true,
            "version": "v17"
          }
        },
        "hostname": "Antoniusweg12",
        "system": {
          "site_code": "ffmsd03"
        },
        "node_id": "60e327ee58a0"
      },
      "lastseen": "2016-04-14T12:39:04",
      "flags": {
        "gateway": false,
        "online": true
      },
      "firstseen": "2016-03-16T15:14:04",
      "statistics": {
        "clients": 1,
        "gateway": "de:ad:be:ef:43:02",
        "rootfs_usage": 0.6041666666666667,
        "loadavg": 0.09,
        "uptime": 1822037.41,
        "memory_usage": 0.8124737210932025,
        "traffic": {
          "rx": {
            "packets": 50393821,
            "bytes": 5061895206
          },
          "forward": {
            "packets": 173,
            "bytes": 17417
          },
          "mgmt_rx": {
            "packets": 47453745,
            "bytes": 6623785282
          },
          "tx": {
            "packets": 1205695,
            "bytes": 173509528,
            "dropped": 5683
          },
          "mgmt_tx": {
            "packets": 37906725,
            "bytes": 11475209742
          }
        }
      }
    },
    "30b5c2b042f4": {
<next block...>

我想用 jq 查询它的主机名,mac 或 IPv6。

cat nodes.json |jq -c '.nodes[] | select(.nodes[]| contains("Antoniusweg12"))'

大多数示例不适合这种 json 结构,因为对象具有索引

提前感谢您的帮助。

如果您要进行筛选,则需要深入到要检查的 属性 并查看它是否符合您的条件。你不能指望只要给一个名字,你就会神奇地得到你想要的结果。

通过主机名搜索,在每个节点的.nodeinfo.hostname 属性上找到:

$ jq -c --arg hostname "Antoniusweg12" \
'.nodes[] | select(.nodeinfo.hostname == $hostname)' nodes.json

与 mac 地址类似,它位于 .nodeinfo.network.mac 属性:

$ jq -c --arg mac "aa:bb:cc:dd:ee:ff" \
'.nodes[] | select(.nodeinfo.network.mac == $mac)' nodes.json

对于 ip 地址,有一个数组,但在查询中并没有太大的不同。它们位于 .nodeinfo.network.addresses 属性:

$ jq -c --arg ip "aaaa:bbbb:cccc:dddd::1" \
'.nodes[] | select(.nodeinfo.network.addresses[] == $ip)' nodes.json

这是对这个问题的另一种看法。假设您要查找值为 "Antoniusweg12" 的键 "hostname" 的所有匹配项, 无论 key/value 组合出现在哪里。

以下将揭示通往感兴趣的 key/value 组合的路径:

paths as $p
| select ( $p[-1] == "hostname" and getpath($p) == "Antoniusweg12" )
| $p

给定输入的结果 JSON:

[
  "nodes",
  "60e327ee58a0",
  "nodeinfo",
  "hostname"
]

如果您想要包含对象的路径,请将最后的 $p 替换为 $p[0:-1];如果你想要包含对象本身:getpath($p[0:-1])

这是一个搜索节点的解决方案,其中指定的 $needle 出现在任何 addressesmachostname 字段中。

  "<ipv6 removed>" as $needle   # set to whatever you like

| foreach (.nodes|keys[]) as $k (
     .
   ; .
   ;    (      .nodes[$k].nodeinfo.network.addresses?
         + [   .nodes[$k].nodeinfo.network.mac?
             , .nodes[$k].nodeinfo.hostname?
           ]
        ) as $haystack

     | if $haystack | index($needle)
       then {($k): .nodes[$k]}
       else empty
       end
  )

编辑:我现在意识到 foreach E as $X (.; .; R) 形式的过滤器几乎总是可以重写为 E as $X | R 所以上面实际上只是

  "<ipv6 removed>" as $needle

| (.nodes|keys[]) as $k
| (      .nodes[$k].nodeinfo.network.addresses?
   + [   .nodes[$k].nodeinfo.network.mac?
       , .nodes[$k].nodeinfo.hostname?
     ]
  ) as $haystack

| if $haystack | index($needle)
  then {($k): .nodes[$k]}
  else empty
  end