jq:按属性分组和键
Posted
技术标签:
【中文标题】jq:按属性分组和键【英文标题】:jq: group and key by property 【发布时间】:2017-08-30 11:50:18 【问题描述】:我有一个如下所示的对象列表:
[
"ip": "1.1.1.1",
"component": "name1"
,
"ip": "1.1.1.2",
"component": "name1"
,
"ip": "1.1.1.3",
"component": "name2"
,
"ip": "1.1.1.4",
"component": "name2"
]
现在我想按组件对其进行分组和键入,并为每个组件分配一个 ips 列表:
"name1": [
"1.1.1.1",
"1.1.1.2"
]
,
"name2": [
"1.1.1.3",
"1.1.1.4"
]
【问题讨论】:
【参考方案1】:我自己想通了。我首先按.component
分组,然后创建新的ips 列表,这些ips 由每个组的第一个对象的组件索引:
jq ' group_by(.component)[] | (.[0].component): [.[] | .ip]'
【讨论】:
如果密钥是数字类型怎么办? @branquito 它不能。对象键始终是 JSON 中的字符串。如果你有一个像"0": 1
这样的 JSON,你可以使用 ."0"
获取 "0"
密钥。
此查询产生的输出不是有效的 json。您可以在我最近发布的这个答案中找到进一步的解释:***.com/a/69346071/2508466【参考方案2】:
作为@replay's technique的进一步示例,在使用其他方法多次失败后,我终于构建了一个过滤器来浓缩这个Wazuh报告(为简洁而摘录):
"took" : 228,
"timed_out" : false,
"hits" :
"total" :
"value" : 2806,
"relation" : "eq"
,
"hits" : [
"_source" :
"agent" :
"name" : "100360xx"
,
"data" :
"vulnerability" :
"severity" : "High",
"package" :
"condition" : "less than 78.0",
"name" : "Mozilla Firefox 68.11.0 ESR (x64 en-US)"
,
"_source" :
"agent" :
"name" : "100360xx"
,
"data" :
"vulnerability" :
"severity" : "High",
"package" :
"condition" : "less than 78.0",
"name" : "Mozilla Firefox 68.11.0 ESR (x64 en-US)"
,
...
这是我用来提供对象数组的jq
过滤器,每个对象都包含一个代理名称,后跟一个代理易受攻击包的名称数组 :
jq ' .hits.hits |= unique_by(._source.agent.name, ._source.data.vulnerability.package.name) | .hits.hits | group_by(._source.agent.name)[] | (.[0]._source.agent.name): [.[]._source.data.vulnerability.package | .name ]'
这是过滤器产生的输出的摘录:
"100360xx": [
"Mozilla Firefox 68.11.0 ESR (x64 en-US)",
"VLC media player",
"Windows 10"
]
"WIN-KD5C4xxx": [
"Windows Server 2019"
]
"fridxxx": [
"java-1.8.0-openjdk",
"kernel",
"kernel-headers",
"kernel-tools",
"kernel-tools-libs",
"python-perf"
]
"mcd-xxx-xxx": [
"dbus",
"fribidi",
"gnupg2",
"graphite2",
...
【讨论】:
【参考方案3】:接受的答案不会产生有效的 json,但是:
"name1": [
"1.1.1.1",
"1.1.1.2"
]
"name2": [
"1.1.1.3",
"1.1.1.4"
]
name1
和 name2
是有效的 json 对象,但作为一个整体的输出不是。
以下jq
语句会产生问题中指定的所需输出:
group_by(.component) | map( key: (.[0].component), value: [.[] | .ip] ) | from_entries
输出:
"name1": [
"1.1.1.1",
"1.1.1.2"
],
"name2": [
"1.1.1.3",
"1.1.1.4"
]
欢迎提出更简单方法的建议。
如果人类可读性优于有效的 json,我会建议类似 ...
jq -r 'group_by(.component)[] | "IPs for " + .[0].component + ": " + (map(.ip) | tostring)'
...导致...
IPs for name1: ["1.1.1.1","1.1.1.2"]
IPs for name2: ["1.1.1.3","1.1.1.4"]
【讨论】:
以上是关于jq:按属性分组和键的主要内容,如果未能解决你的问题,请参考以下文章