我有一个像这样行的文件:
{"items":["blue","green"]}
{"items":["yellow","green"]}
{"items":["blue","pink"]}
如何使用jq选择并仅显示在其“项目”数组中具有“蓝色”的 JSON 值?
所以输出将是:
{"items":["blue","green"]}
{"items":["blue","pink"]}
找到了答案
jq 'select(.items | index("blue"))'
2017 年 1 月 30 日,IN
添加了一个名为的内置函数,用于有效测试 JSON 实体是否包含在流中。它还可以用于有效地测试数组中的成员资格。在本案中,相关用法为:
select( .items as $items | "blue" | IN($items[]) )
如果你的 jq 没有IN/1
,那么只要你的 jq 有first/1
,你就可以使用这个等价的定义:
def IN(s): . as $in | first(if (s == $in) then true else empty end) // false;
在这里使用any/0
效率相对较低,例如与使用相比any/1
:
select( any( .items[]; . == "blue" ))
(实际上,index/1
通常速度足够快,但目前(jq 1.5 和至少到 2017 年 7 月的版本)的实现并不理想。)
虽然你所拥有的肯定有效,但使用contains
. 我会避免这种使用,因为它会导致混乱。 index("blue")
是0
并且人们不会认为这是一个真实的值,并且可能会期望它被排除在结果之外。
考虑改用这个过滤器:
select(.items | contains(["blue"]))
这有一个额外的好处,如果您想要通过简单地向数组添加更多匹配项来匹配多个匹配项,它会起作用。
正如威尔在评论中指出的那样,这并不完全正确。字符串在此处使用子字符串匹配(contains
递归使用)进行比较。
回想起来,contains
并没有像我想象的那样成功。使用index
作品,但我个人不会使用它。通过查找对我来说感觉不对的索引来确定一个项目是否在集合中。使用contains
对我来说更有意义,但鉴于这些信息,在这种情况下它并不理想。
这是一个应该正常工作的替代方案:
select([.items[] == "blue"] | any)
或者,如果您希望能够匹配更多值,则可以采用更具可扩展性的方式:
select(.items as $values | ["blue", "yellow"] | map([$values[] == .] | any) | all)
对于对象的相同情况,我需要使用“正则表达式”。(当然,在另一种情况下)。我编写代码是因为我没有在这些页面中找到满足我需求的解决方案。这可能对某人有用。
例如,要使用正则表达式匹配蓝色:
jq 'select(.items[]|test("bl.*"))' yourfile.json