我和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
做这样的事情的最佳方法是什么?
答案 0 :(得分:6)
IRC用户gnomon在jq channel上回答了这个问题,如下所示:
jq 'select([.author] | inside(["Larry", "Garry", "Jerry"]))'
用户所说的这种方法背后的直觉是:“字面意思是你的想法,只将.author
包裹为[.author]
以强迫它成为单项数组inside()
将继续努力。“这个答案产生了对列表中提供的一系列名称进行过滤所需的结果,作为原始问题。
答案 1 :(得分:3)
inside
和contains
有点奇怪。以下是一些更直接的解决方案:
select( .author as $a | ["Gary", "Larry"] | index($a) )
["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