首页 > 解决方案 > jq中根据相似ID对象合并文件并改造数据

问题描述

前言:如果 jq 无法做到以下几点,那么我完全接受它作为答案,并将尝试用 bash 强制执行此操作。

我有两个文件,其中包含一些 ID,通过一些按摩,应该能够组合成一个文件。我也会添加一些内容(如输出所示)。本质上,“mitre_test”应该与“sys_id”进行比较。比较时,来自 in2.json 的“mitreid”在输出中变成了 technology_ID(通常是每个输出对象的统一字段)。

注意事项:

  1. 在 in1.json 中放置了一些垃圾“desc”值,以确保它尽可能编程,并且在我正在使用的真实输入文件中实际上有许多垃圾输入。

  2. 一些 mitre_test 值有对并且不在真实数组中。我可以拆分这些并将它们分开,但发现自己丢失了 in1.json 中的其他信息。

  3. 请注意,输出的“元数据”中包含来自 in1.json 的“数字”值,并以奇怪的方式存储(但接收工具需要的方式)。

in1.json

[
{
  "test": "Execution",
  "mitreid": "T1204.001",
  "mitre_test": "90b"
},
{
  "test": "Defense Evasion",
  "mitreid": "T1070.001",
  "mitre_test": "afa"
},
{
  "test": "Credential Access",
  "mitreid": "T1556.004",
  "mitre_test": "14b"
},
{
  "test": "Initial Access",
  "mitreid": "T1200",
  "mitre_test": "f22"
},
{
  "test": "Impact",
  "mitreid": "T1489",
  "mitre_test": "fa2"
}
]

in2.json

[
  {
    "number": "REL0001346",
    "desc": "apple",
    "mitre_test": "afa"
  },
  {
    "number": "REL0001343",
    "desc": "pear",
    "mitre_test": "90b"
  },
  {
    "number": "REL0001366",
    "desc": "orange",
    "mitre_test": "14b,f22"
  },
  {
    "number": "REL0001378",
    "desc": "pineapple",
    "mitre_test": "90b"
  }
]

输出:

[{
  "techniqueID": "T1070.001",
  "tactic": "defense-evasion",
  "score": 1,
  "color": "",
  "comment": "",
  "enabled": true,
  "metadata": [{
      "name": "DET_ID",
      "value": "REL0001346"
    }],
  "showSubtechniques": true
},
{
  "techniqueID": "T1204.001",
  "tactic": "execution",
  "score": 1,
  "color": "",
  "comment": "",
  "enabled": true,
  "metadata": [{
      "name": "DET_ID",
      "value": "REL0001343"
    },
    {
      "name": "DET_ID",
      "value": "REL0001378"
    }],
  "showSubtechniques": true
},
{
  "techniqueID": "T1556.004",
  "tactic": "credential-access",
  "score": 1,
  "color": "",
  "comment": "",
  "enabled": true,
  "metadata": [{
      "name": "DET_ID",
      "value": "REL0001366"
    }],
  "showSubtechniques": true
},
{
  "techniqueID": "T1200",
  "tactic": "initial-access",
  "score": 1,
  "color": "",
  "comment": "",
  "enabled": true,
  "metadata": [{
      "name": "DET_ID",
      "value": "REL0001366"
    }],
  "showSubtechniques": true
}
]

我假设我要在 mitre_test 上使用类似的东西进行一些拆分.mitre_test |= split(",")),并且我假设有一些连接,但是这样做会导致数据丢失或数据混淆。您会注意到输出中的静态数据也存在,但可能很容易放入,因此问题不大。

编辑:减少了一些匹配 ID,以便在分析 in1 和 in2 文件时更容易查看。还简化了两个输入以具有相似的结构,以便以后更容易理解答案。

标签: jsonjq

解决方案


要求有些不透明,但很明显,如果任务可以通过计算机完成,则可以使用 jq 完成。

从描述中可以看出,问题的一个不寻常的方面是 in1.json 定义的“字典”必须通过拆分 CSV(逗号分隔值)的键名来派生。因此,这里有一个 jq def 可以做到这一点:

# Input: a JSON dictionary for which some keys are CSV,
# Output: a JSON dictionary with the CSV keys split on the commas
def refine:
  . as $in
  | reduce keys_unsorted[] as $k ({};
    if ($k|index(","))
    then ($k/",") as $keys
    | . + ($keys | map( {(.): $in[$k]}) | add)
    else .[$k] = $in[$k]
    end );

您可以通过运行查看其工作原理:

INDEX($mitre.records[]; .mitre_test) | refine

使用 jq 的调用,例如:

jq --argfile mitre in1.json -f program.jq in2.json

对于问题的加入部分,有很多关于SO的相关问答,例如

如何使用 jq 在特定字段上加入 JSON 对象?


推荐阅读