仅从 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 中的外部文件中过滤特定键的主要内容,如果未能解决你的问题,请参考以下文章