根据jq

时间:2017-06-22 16:02:39

标签: json jq whitelist

我和JQ一起工作,到目前为止我非常喜欢它。我遇到了一个问题,但我还没有找到其他任何地方的解决方案,并希望看看社区是否有办法实现这一目标。

假设我们有一个类似的JSON文件:

{"author": "Gary", "text": "Blah"}
{"author": "Larry", "text": "More Blah"}
{"author": "Jerry", "text": "Yet more Blah"}
{"author": "Barry", "text": "Even more Blah"}
{"author": "Teri", "text": "Text on text on text"}
{"author": "Bob", "text": "Another thing to say"}

现在,我们要选择author的值等于" Gary"或"拉里",但没有其他情况。实际上,我有几千个我要检查的名字,所以简单地说明直接或条件(例如cat blah.json | jq -r 'select(.author == "Gary" or .author == "Larry")')是不够的。我尝试通过inside函数执行此操作,但得到错误对话框:

cat blah.json | jq -r 'select(.author | inside(["Gary", "Larry"]))'

jq: error (at <stdin>:1): array (["Gary","La...) and string ("Gary") cannot have their containment checked

做这样的事情的最佳方法是什么?

3 个答案:

答案 0 :(得分:6)

IRC用户gnomon在jq channel上回答了这个问题,如下所示:

jq 'select([.author] | inside(["Larry", "Garry", "Jerry"]))'

用户所说的这种方法背后的直觉是:“字面意思是你的想法,只将.author包裹为[.author]以强迫它成为单项数组inside()将继续努力。“这个答案产生了对列表中提供的一系列名称进行过滤所需的结果,作为原始问题。

答案 1 :(得分:3)

insidecontains有点奇怪。以下是一些更直接的解决方案:

索引/ 1

select( .author as $a | ["Gary", "Larry"] | index($a) )

任/ 2

["Gary", "Larry"] as $whitelist
| select( .author as $a | any( $whitelist[]; . == $a) )

使用字典

如果性能是一个问题,如果“author”始终是一个字符串,那么应该考虑@JeffMercado建议的解决方案。这是一个变体(与-n命令行选项一起使用):

["Gary", "Larry"] as $whitelist
| ($whitelist | map( {(.): true} ) | add) as $dictionary
| inputs
| select($dictionary[.author])

答案 2 :(得分:2)

您可以像使用对象一样使用对象来测试成员身份。在数组上运行的方法效率很低,特别是如果数组可能很大。

您可以在读取输入之前构建一组值,然后使用该集来过滤输入。

$ jq -n --argjson names '["Larry","Garry","Jerry"]' '
(reduce $names[] as $name ({}; .[$name] = true)) as $set
    | inputs | select($set[.author])
' blah.json