首页 > 解决方案 > 使用 bash 字符串作为 jq 过滤器

问题描述

我不明白我做错了什么或为什么这不起作用。

test.json文件:

[
  {
    "Header": {
      "Region": "US",
      "Tenant": "Tenant1",
      "Stage": "testing",
      "ProductType": "old"
    },
    "Body": []
  },
  {
    "Header": {
      "Region": "EU",
      "Tenant": "Tenant2",
      "Stage": "development",
      "ProductType": "new"
    },
    "Body": []
  }
]

我想显示.Header.Tenant键的值。所以简单的 jq 调用就完成了它的工作:

$ jq '[.[].Header.Tenant]' test.json
[
  "Tenant1",
  "Tenant2"
]

现在我想将该 jq 过滤器分配给一个 bash 变量并将其与 jq 的--arg变量一起使用。

我得到了这个:

$ a=".[].Header.Tenant"; jq --arg xx "$a" '[$xx]' test.json
[
  ".[].Header.Tenant"
]

怎么了?

标签: bashfilteringevaljq

解决方案


jq 没有eval评估任意 jq 表达式的函数,但它确实提供了可用于实现大致相同效果的函数,关键思想是某些 JSON 值可用于指定查询操作。

在您的情况下,您必须将 jq 查询转换为合适的 jq 操作,例如:

jq --argjson a '["Header","Tenant"]' '
   getpath(paths|select( .[- ($a|length) :]== $a))
' test.json

扩展 jq 的基于 JSON 的查询语言

更有趣的是,您可以编写自己的eval,例如

jq --argjson a '[[], "Header","Tenant"]' '

  def eval($expr):
    if $expr == [] then .
    else $expr[0] as $op
    | if $op == [] then .[] | eval($expr[1:])
      else getpath([$op]) | eval($expr[1:])
      end
    end;
   eval($a)
' test.json

以 eval.jq 为模块

如果将上面的 defeval放在一个文件中,比如 ~/jq/eval.jq,那么你可以简单地写:

jq -L ~/jq --argjson a '[[], "Header","Tenant"]' '
  include "eval";
  eval($a)' test.json

或者您可以在 jq 程序中指定搜索路径:

jq --argjson a '[[], "Header","Tenant"]' '
  include "eval" { "search": "~/jq" };
  eval($a)' input.json

或者你可以使用import...


推荐阅读