假设我有一个 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

  • 应该输出什么:{"k": [ "foo", "bar" ] }


    – 


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 ... thenif $x==[] then并更改empty endempty 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