在jq
脚本中,我需要使用路径值对(比旧的键值对更通用)创建 json 对象。也就是说,我需要使用路径而不是键,以便在更深层次上创建值。(这些路径是外部提供的,所以我事先不知道它们。)
例如,在非工作伪代码中,我想使用路径来创建这样的对象:
jq -n '{"a"."x" : 3, "b"."y" : 4}'
这样它就会创建相同的 json 对象jq -n '{"a":{"x" : 3}, "b":{"y" : 4}}'
,即
{
"a": {
"x": 3
},
"b": {
"y": 4
}
}
在某种程度上,这类似于mdir -p
允许直接创建一个包含路径上所有祖先目录的目标目录。但我需要对(许多)json 对象执行此操作。因此,问题是:
使用本机 jq(可能加上一些 bash)通过路径值对创建对象的最简单方法是什么?
(我正在寻找一种复杂度较低且不需要进行大量编程的解决方案。这是在 Ubuntu 24.04 LTS 下使用 jq-1.7.1 实现的)
-- 澄清 --
我想到的输入是路径列表加上值列表,例如:
[".a.x", ".b.y"]
和
[3, 4]
。路径由点分隔。为简单起见,我假设点之间的每个部分都是一个简单的标识符,例如y
(而不是复杂的标识符,例如"y.z"
)。也就是说,我不考虑(目前)这样的路径:
[".a.x", ".b.\"y.z\""]
表达式
jq
首先将x
下方的键设置a
为3
,然后将结果对象通过管道传递到另一个类似的分配中,将同一对象中y
的键设置b
为。4
但是,这使用了静态路径
.a.x
和.b.y
。您是否想要使用从 shell 给出的数据,然后您可以对两个值执行以下操作:
这用于
setpath()
将命令行末尾的列表给出的路径(第一个实例中)设置a
为x
变量的值$value
。然后将结果传递给类似的jq
调用,该调用在另一个路径上添加第二个值(但请注意这里缺少-n
!)如果应将值添加为字符串(而不是数字),则在给出值时使用--arg
代替。--argjson
该管道的结果是
根据 shell 中路径的形式,您可能会发现将完整构造的路径数组传递给很有用
jq
:.a.x
如果您有形式为和的路径.b.y
,那么您可以使用将它们拆分为以split()
形成路径数组setpath()
:[1:]
仅当您的路径字符串以点开头时,才需要结果。split()
请注意,这是此解决方案的第一个变体,不允许键名称中使用点。考虑到您的澄清意见,您可以使用
这首先从两个数组和的每个组合元素创建一个
$p
("path") 和("value") 对。然后以与之前类似的方式拆分字符串,并使用 将值分配给它。$v
$path
$value
$p
$v
setpath()
这里唯一的“魔法”是初始的
[$path,$value] | transpose[]
,它生成两个数组...整个操作发生在数组构造函数中,形成数组
...
add
然后结合成我们的最终产品:再次,键字符串中不允许使用点,并且我们还假设输入数组的长度始终相同。