在jq

时间:2016-11-01 04:33:34

标签: json select filtering identifier jq

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

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

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

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

1 个答案:

答案 0 :(得分:3)

基本上有两种方法可以继续:

  1. 从STDIN
  2. 读取ID文件
  3. 从STDIN
  4. 读取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