我正在尝试搜索具有特定属性的对象,然后更新另一个属性。鉴于此输入:
[
{
"replacements": [
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
},
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
},
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.ghi.image.tag"
}
],
"yamlFilePath": "k8s/helm/Dev/us-east-1/values.yaml"
}
]
并将占位符 ( abc-image-tag
for k8s-helm-templates.deployment.containers.abc.image.tag
) 用作:
[
{"name":"abc-image-tag","value":"123"},
{"name":"def-image-tag","value":"456"}
]
应该得到的结果是给定值被正确替换并且 0 值被过滤,如下所示:
[
{
"replacements": [
{
"newValue": "123",
"yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
},
{
"newValue": "456",
"yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
}
],
"yamlFilePath": "k8s/helm/Dev/us-east-1/values.yaml"
}
]
尝试了一些技巧并深入研究了文档,但似乎无法让它发挥作用。这对于 jq 来说是可能的吗?使用 bash 执行其他步骤就可以了
答案1
尝试这个:
jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
def placeholder_index: .name | gsub("-"; ".") ;
def replacement_index: .yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "") ;
def replace($placeholders):
[
JOIN(INDEX(.[]; replacement_index); $placeholders[]; placeholder_index) |
{newvalue: .[0].value, yamlPath: .[1].yamlPath}
]
;
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
$replacements | .[0].replacements |= replace($placeholders)
'
我可以通过展示我为实现这一目标而构建的原型来解释它。
我假设每个输入都在一个文件中。
cat > replacements.json <<"EOF"
[
{
"replacements": [
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
},
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
},
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.ghi.image.tag"
}
],
"yamlFilePath": "k8s/helm/Dev/us-east-1/values.yaml"
}
]
EOF
cat > placeholders.json <<"EOF"
[
{"name":"abc-image-tag","value":"123"},
{"name":"def-image-tag","value":"456"}
]
EOF
第一个技巧是获取每个输入的句柄。如果只有一个输入,您通常会从标准输入中读取它,并.
在管道开始时引用它。当您有多个输入时,您可以使用--rawfile
将每个 JSON 文本加载到命名变量中。当没有明显的“主”输入时,您可以使用--null-input
jq 不从标准输入读取。
--rawfile
读取一个字符串,因此需要使用它fromjson
来解析一个JSON对象。您还可以用来--slurpfile
读取 JSON 对象数组,但您需要挑选第一个元素,因此这仍然是一个额外的步骤。
jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
$replacements, $placeholders
'
您想要的结果看起来像两个 SQL 数据库表之间的内部联接。我这么说是因为 jq 有“SQL 风格的运算符”,可以实现类似的操作。它们的记录很少,所以我在这里通过反复试验找出了它们。
用于INDEX
生成一个对象,该对象将输入流中的每个对象映射到一个键,并用于JOIN
对两个索引执行内部联接。
的索引$replacements
看起来像这样。这里的关键表达式删除了公共前缀以yamlPath
留下可变图像标签。
jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
INDEX(
$replacements[0].replacements[];
.yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "")
)
'
{
"abc.image.tag": {
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
},
"def.image.tag": {
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
},
"ghi.image.tag": {
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.ghi.image.tag"
}
}
的索引$placeholders
看起来像这样。键表达式将破折号替换为点,以便变量图像标签看起来像 的标签$replacements
。
jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
INDEX($placeholders[]; .name | gsub("-"; "."))
'
{
"abc.image.tag": {
"name": "abc-image-tag",
"value": "123"
},
"def.image.tag": {
"name": "def-image-tag",
"value": "456"
}
}
您将看到两个索引对象中的一些键匹配。这就是我们如何获得JOIN
对这些对象进行内部连接的函数。
实际上,您INDEX
只需调用一次,因为JOIN
无论如何该函数都会有效地创建第二个索引。
JOIN
返回“对”列表的流,其中第一个对象来自流输入,第二个对象来自索引输入。
jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
JOIN(
INDEX(
$replacements[0].replacements[];
.yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "")
);
$placeholders[];
.name | gsub("-"; ".")
)
'
[
{
"name": "abc-image-tag",
"value": "123"
},
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
}
]
[
{
"name": "def-image-tag",
"value": "456"
},
{
"newValue": "0",
"yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
}
]
下一步是创建一个新对象,该对象从每个连接的对象中“选择”正确的属性来创建新对象,然后将输出包装JOIN
在数组中。
jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
[
JOIN(
INDEX(
$replacements[0].replacements[];
.yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "")
);
$placeholders[];
.name | gsub("-"; ".")
) |
{newvalue: .[0].value, yamlPath: .[1].yamlPath}
]
'
[
{
"newvalue": "123",
"yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
},
{
"newvalue": "456",
"yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
}
]
最终的解决方案定义了一些函数来为每个表达式命名。它使用更新赋值运算|=
符来复制原始结构$replacements
并使用连接结果更新内部列表。