【发布时间】:2025-11-21 09:45:02
【问题描述】:
我有以下名为 CMakePresets.json 的 json 文件,它是一个 cmake 预设文件:
{
"configurePresets": [
{
"name": "default",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/_build/${presetName}",
"cacheVariables": {
"YIO_DEV": "1",
"BUILD_TESTING": "1"
}
},
{
"name": "debug",
"inherits": "default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"inherits": "default",
"binaryDir": "${sourceDir}/_build/Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "arm",
"inherits": "debug",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/Toolchain/arm-none-eabi-gcc.cmake"
}
}
]
}
我想递归地与 * 合并 configurePresets 元素,这些元素为特定条目 name 继承自身。我有一个名为arm 的节点示例,并且希望生成具有已解析继承的json 对象。父元素的名称存储在每个元素的 .inherits 中。 arm 继承于 debug,后者继承于 default。
在Remove a key:value from an JSON object using jq 和this answer 的帮助下,我可以编写一个我认为可行的 bash shell 循环:
input=arm
# extract one element
g() { jq --arg name "$1" '.configurePresets[] | select(.name == $name)' CMakePresets.json; };
# get arm element
acc=$(g "$input");
# If .inherits field exists
while i=$(<<<"$acc" jq -r .inherits) && [[ -n "$i" && "$i" != "null" ]]; do
# remove it from input
a=$(<<<"$acc" jq 'del(.inherits)');
# get parent element
b=$(g "$i");
# merge parent with current
acc=$(printf "%s\n" "$b" "$a" | jq -s 'reduce .[] as $item ({}; . * $item)');
done;
echo "$acc"
输出,我认为这是arm 的预期输出:
{
"name": "arm",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/_build/${presetName}",
"cacheVariables": {
"YIO_DEV": "1",
"BUILD_TESTING": "1",
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/Toolchain/arm-none-eabi-gcc.cmake"
}
}
但我想写在jq。我试过了,jq 语言对我来说并不直观。例如,我可以为两个(即可数)元素做到这一点:
< CMakePresets.json jq --arg name "arm" '
def g(n): .configurePresets[] | select(.name == n);
g($name) * (g($name) | .inherits) as $name2 | g($name2)
'
但是当$item 真的是g($name) 这取决于最后一个g($name) | .inherits 时,我不知道该怎么做reduce .[] as $item ({}; . * $item)。我尝试阅读 jq manual 并了解变量和循环,但 jq 的语法非常不同。我尝试使用while,但这只是我不理解且不知道如何修复的语法错误。我猜while 和until 可能不在此处,因为它们对先前的循环输出进行操作,而元素始终来自根目录。
$ < CMakePresets.json jq --arg name "arm" 'def g(n): .configurePresets[] | select(.name == n);
while(g($name) | .inherits as $name; g($name))
'
jq: error: syntax error, unexpected ';', expecting '|' (Unix shell quoting issues?) at <top-level>, line 2:
while(g($name) | .inherits as $name; g($name))
jq: 1 compile error
如何用jq 语言编写这样的循环?
【问题讨论】:
标签: json inheritance merge jq ancestor