【问题标题】:How to replace values in a JSON dictionary with their respective shell variables in jq?如何用 jq 中各自的 shell 变量替换 JSON 字典中的值?
【发布时间】:2022-01-10 00:12:41
【问题描述】:

我有以下 JSON 结构:

{
  "host1": "$PROJECT1",
  "host2": "$PROJECT2",
  "host3" : "xyz",
  "host4" : "$PROJECT4"
}

以及shell中的以下环境变量:

PROJECT1="randomtext1"
PROJECT2="randomtext2"
PROJECT4="randomtext3"

我想检查每个键的值,如果它们有一个“$”字符,请将它们替换为它们各自的环境变量(它已经存在于 shell 中),以便我的 JSON 模板以正确的方式呈现环境变量。

我可以使用 jq 的 --args 选项,但我想要渲染的实际 JSON 模板中有很多变量。

我一直在尝试以下方法:

jq 'with_entries(.values as v | env.$v)

基本上将每个值作为变量,然后使用 env 对象中的变量更新其值,但似乎我错过了一些理解。有没有一种简单的方法可以做到这一点?

编辑

感谢对这个问题的回答,我能够实现我更大的目标,其中一部分被问到这个问题

  • 遍历对象中的每个值,
  • 检查其值,
    • 如果它是一个字符串并且以字符“$”开头
      • 使用该值将其更新为同名的环境变量。
    • 如果它是一个数组
      • 使用该值检索同名的环境变量
      • 用“,”作为分隔符分割字符串,返回一个字符串数组
      • 用字符串数组更新值
         
jq 'with_entries(.value |= (if (type=="array") then (env[.[0][1:]] | split(",")) elif (type=="string" and startswith("$")) then (env[.[1:]]) else  . end))'

【问题讨论】:

  • 由于 $PROJECT4,所示模板作为 JSON 不太有效。请澄清并更正描述或模板。
  • 我的错,已更正。

标签: json shell environment-variables jq


【解决方案1】:

您需要exportjq 看到的 Bash 变量:

export PROJECT1="randomtext1"
export PROJECT2="randomtext2"
export PROJECT4="randomtext3"

然后你可以去:

jq -n 'with_entries((.value | select(startswith("$"))) |= env[.[1:]])'

然后得到:

{
  "host1": "randomtext1",
  "host2": "randomtext2",
  "host3": "xyz",
  "host4": "randomtext3"
}

【讨论】:

  • 是的,行得通!非常感谢。你能解释一下env[] 会发生什么吗?它是否从env 对象中创建了一个数组?我被困在这一点上。另外,如果其中一个值是数组怎么办?过滤器似乎失败了,因为它只需要字符串值。
  • env 输出一个代表 jq 当前环境的对象。与任何对象一样,您可以使用例如访问字段(表示环境变量)。 env.PROJECT2。这(仍然与任何对象一样)等同于使用env.["PROJECT2"]。除了输入/上下文的第一个字符.[1:](剥离$ 字符)之外,我使用的不是文字字符串,由于更新运算符|= 是左侧的值,即内容要更新的字段(selected .value)。
  • 感谢您的解释。我得到了拼接部分,但是,使用env.["PROJECT2"] 而不是env.PROJECT2 似乎不起作用。 env[] 将根据我的理解返回变量的所有值。 env[] 中的 [] 是否在这里充当分组容器?只是想正确理解这部分。
  • 对不起,它应该是env["PROJECT2"]。而单独的.[](或在本例中为env[])将数组或对象转换为其值的流。
  • 是的,这让我很困惑。我以为env[] 给了我一个值流,我怎么能从那里引用这个值。
【解决方案2】:

导出大量的 shell 变量可能不是一个好主意,也不能解决数组值变量的问题。因此,按照将 variable=value 详细信息打印到文件,然后将该文件与模板组合起来的思路进行思考可能是一个好主意。这很容易做到,互联网上的例子比比皆是,可能在 SO 上也是如此。例如,您可以像这样使用printf

printf "%s\t" ${BASH_VERSINFO[@]}
3   2   57  1   

您可能还会发现declare -p 很有帮助。

另见https://github.com/stedolan/jq/wiki/Cookbook#arbitrary-strings-as-template-variables

【讨论】:

  • 嘿,感谢您向我指出该资源。我试过了,效果很好。
猜你喜欢
  • 2019-09-10
  • 2019-04-13
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 2018-09-20
  • 2016-12-15
  • 1970-01-01
相关资源
最近更新 更多