【问题标题】:Combine files in jq based on similar ID object and reform datajq中根据相似的ID对象合并文件并重组数据
【发布时间】:2021-02-25 19:56:19
【问题描述】:

前言:如果 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 文件时更容易查看。还简化了两个输入以具有相似的结构,以便以后更容易理解答案。

【问题讨论】:

  • 我假设我需要首先将相似的值重命名为相同的值,然后将它们重命名为相同的值,然后 jq . in1.json in2.json 并首先将类似的项目组合在一起。我将继续研究这个问题,并希望能回答我自己的问题,因为我知道这个问题比一般人更喜欢的问题更深入。
  • 我越来越接近以下jq . in4.json in3.json | jq '.[] |{number: .number, test: .test, mitreid: .mitreid, mitre_test: .mitre_test}' | jq -s '. |map(try(.mitre_test |= split(",")) // .)| .[] | [.number,.test,.mitreid] as $h | .mitre_test[] |$h + [.] | {DET_ID: .[0], tactic: .[1], techniqueID: .[2], mitre_test: .[3]}'

标签: json jq


【解决方案1】:

要求有些不透明,但很明显,如果任务可以通过计算机完成,则可以使用 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的相关Q&A,例如

How to join JSON objects on particular fields using jq?

【讨论】:

    【解决方案2】:

    可能有一种更优雅的方式来做到这一点,但我最终手动走动并管道到新的输出。

    说明: 读入两个文件,拉出我需要的字段。

    使用 map 拆分以前只是逗号分隔的一组值的 mitre_test 值并尝试。

    将不变的字段存储为变量,然后操作 mitre_test 成为一个适当拆分的数组,删除空值。 按 mitre_test 值分组,因为它们是输出所基于的常见事物。

    清理更多的空值。

    对输出进行排序,使其看起来像我想要的那样。

    jq . in1.json in2.json | \
    jq '.[] |{number: .number, test: .test, mitreid: .mitreid, mitre_test: .mitre_test}'  |\
    jq -s '[. |map(try(.mitre_test |= split(",")) // .)|\
    .[] | [.number,.test,.mitreid] as $h | .mitre_test[] |$h + [.] | \
    {DET_ID: .[0], tactic: .[1], techniqueID: .[2], mitre_test: .[3]}] |\
    del(.[][] | nulls)' |jq '[group_by(.mitre_test)[]|{mitre_test: .[0].mitre_test, techniqueID: [.[].techniqueID],tactic: [.[].tactic], DET_ID: [.[].DET_ID]}]|\
    del(.[].techniqueID[] | nulls) | del(.[].tactic[] | nulls) | del(.[].DET_ID[] | nulls)' | \
    jq '.[]| [{techniqueID: .techniqueID[0],tactic: .tactic[0], metadata: [{name: "DET_ID",value: .DET_ID[]}]}] | .[] | \
    select((.metadata|length)>0)'
    

    这是一条很长的线,所以我把它分成了一些基本的想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-16
      • 1970-01-01
      • 1970-01-01
      • 2020-03-16
      • 2012-12-19
      • 2021-08-17
      • 1970-01-01
      • 2022-12-15
      相关资源
      最近更新 更多