假设我有一个 json 文件。我想过滤此文件以仅输出给定模式出现在完整路径或叶节点值中的任何位置的内容。例如,假设 json 文件具有以下内容:
{
"a": "foo",
"b": "bar",
"c": {
"d": "foo",
"e": "bar"
},
"aa": {
"foo": [
1,
2,
3
],
"bar": {
"foo": false
}
}
}
模式是“foo”。然后,输出应如下所示。
{
"a": "foo",
"c": {
"d": "foo"
},
"aa": {
"foo": [
1,
2,
3
],
"bar": {
"foo": false
}
}
}
那么,jq
命令应该是什么?
1
3 个回答
3
因为我不知道如何编写正确的jq
代码:
jq --stream -c < file.json |
grep -e 'foo' -e ']]$' |
jq -n 'fromstream(inputs)'
或者:
jq --stream -n < file.json '
fromstream(
inputs | select(
(length == 1)
or any(
(.[0][], .[1]) | strings;
test("foo")
)
)
)
'
输入:
{
"a": "foo",
"b": "bar",
"c": {
"d": "foo",
"e": "bar"
},
"aa": {
"foo": [
1,
2,
3
],
"bar": {
"foo": false
},
"delete-this": {
"not": "wanted"
}
},
"delete-all": {
"x": {
"a": {
"b": {
"c": 1
}
}
},
"y": {
"a": [
{
"b": [
1
]
}
]
}
},
"keep-part": [
"foo",
"bar"
]
}
输出:
{
"a": "foo",
"c": {
"d": "foo"
},
"aa": {
"foo": [
1,
2,
3
],
"bar": {
"foo": false
}
},
"keep-part": [
"foo"
]
}
2
-
1最后一个答案非常好,只是用以下内容替换 RHS 会更好
or
:any(.[0][], .[1] | strings; test(“foo”))
– -
1@peak 看到了 oguz 的回答,我实际上只是在阅读
any
操作员:-)
–
|
如果以下内容不完全符合您的期望,那么希望您能够对其进行调整,使其达到预期效果:
def prune(cond):
def prune_object:
. as $in
| reduce keys_unsorted[] as $k ({}; # preserve ordering
if ($k|cond) then .[$k] = $in[$k]
else [$in[$k] | prune(cond)] as $x
| if $x == [] then .
else .[$k] = $x[0]
end
end )
| select(. != {});
if type == "object" then prune_object
elif type == "array"
then map(prune(cond))
| select(. != [])
elif type == "string" then select(cond)
else empty
end;
prune(test"foo"))
这种公式的优点是您可以轻松指定类似的替代方案,例如
修剪(.==“foo”)
或者
修剪(开始于(“foo”))
或者
修剪(测试(“foo”;“i”))
2
-
我添加到我的答案中的“删除全部”测试(基本上
{"a":[{"b":1}]}
)似乎混淆了您的代码。我认为if $x
测试希望在测试输出之后进行if type
,但我不知道足以建议修复
– -
也许简化
if $x ... then
为if $x==[] then
并更改empty end
为empty end | select(.!=[] and .!={})
?
–
|
这是一个方法:
def f:
def g:
def h: type == "string" and test("foo") | not;
del(getpath(
paths(scalars, select(IN([], {}))) | select(all(h))
) | select(h));
. as $in | g | if . != $in then f end;
f
0
|
{"k": [ "foo", "bar" ] }
?–
|