仅过滤 jq 中外部文件中的特定键

Filter only specific keys from an external file in jq

我有一个 JSON 文件,格式如下:

[
  {
    "id": "00001",
    "attr": {
      "a": "foo",
      "b": "bar",
      ...
    }
  },
  {
    "id": "00002",
    "attr": {
      ...
    },
    ...
  },
...
]

和一个包含 ID 列表的文本文件,每行一个。我想使用 jq 仅过滤文本文件中提及其 ID 的记录。 IE。如果列表包含“00001”,则只打印第一个。

请注意,我不能简单地 grep,因为每条记录可能具有任意数量的属性和子属性。

基本上有两种方法可以进行:

  1. 从STDIN读取ids文件
  2. 从 STDIN
  3. 读取 JSON

两者都是可行的,但这里我们说明 (2),因为它会导致一个简单但有效的解决方案。

假设 JSON 文件名为 in.json 并且 ID 列表位于名为 ids.txt 的文件中,如下所示:

00001
00010

请注意,此文件没有引号。如果是这样,那么可以大大简化以下内容,如后记所示。

诀窍是将 ids.txt 转换为 JSON 数组。根据以上关于引号的假设,这可以通过以下方式完成:

jq -R . ids.txt | jq -s .

假设一个合理的shell,现在有一个简单的解决方案:

jq --argjson ids "$(jq -R . ids.txt | jq -s .)" '
  map( select( .id as $id | $ids | index($id) ))' in.json

更快

假设你的 jq 有 any/2,那么一个更简单和更有效的解决方案可以通过定义获得:

def isin($a): . as $in | any($a[]; $in == .);

所需的 jq 过滤器就是:

map( select( .id | isin($ids) ) )

如果将这两行jq放到一个名为select.jq的文件中,需要的咒语就是:

jq --argjson ids "$(jq -R . ids.txt | jq -s)" -f select.jq in.json

后记

如果索引文件由有效的 JSON 文本流组成(例如,带引号的字符串)并且如果您的 jq 支持 --slurpfile 选项,则调用可以进一步简化为:

jq --slurpfile ids ids.txt -f select.jq in.json 

或者,如果您希望所有内容都成为一行:

jq --slurpfile ids ids.txt 'map(select(.id as $id|any($ids[];$id==.)))' in.json