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

Posted

技术标签:

【中文标题】仅从 jq 中的外部文件中过滤特定键【英文标题】:Filter only specific keys from an external file in jq 【发布时间】:2017-03-14 05:51:45 【问题描述】:

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

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

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

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

【问题讨论】:

【参考方案1】:

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

    从 STDIN 读取 ids 文件 从 STDIN 读取 JSON

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

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

00001
00010

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

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

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

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

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 

【讨论】:

谢谢,any 解决方案可以用作单线吗? 另外,由于某种原因,ids="$(jq -R . ids.txt | jq -s)" 给了我jq 的使用信息,但只有jq -R . ids.txt | jq -s 按预期工作。我正在使用 bash。我也尝试添加 -M 来删除颜色,但这没有帮助。 @dimid - 为了稳健,请使用jq -s . 而不仅仅是jq -s。对于那些使用 jq 1.5 的人,已添加了一个多合一的单线。 太好了,谢谢。最终对我有用的是:jq -R . ids.txt > ids2.json; jq --slurpfile ids ids2.json 'map(select(.id as $id|any($ids[];$id==.)))' in.json

以上是关于仅从 jq 中的外部文件中过滤特定键的主要内容,如果未能解决你的问题,请参考以下文章

JQ:过滤键

如何仅从一个键中过滤对象并将其作为 json 返回?

JQ 过滤嵌套对象中的字段

如何按名称过滤键,然后使用 jq 访问嵌套对象

LogParser 查询仅从 IIS 日志中获取外部 IP 地址?

java中的Servlet/过滤器特定异常处理