用新值用 yq 替换 Yaml 值作为接受当前值作为输入的 bash 函数的输出
Substitute Yaml values with yq by new value as output of bash function which accept current value as input
概览
- 类似于Substitution with sed + bash function
但是使用
yq
- yq of kislyuk 而不是其他 yq 项目 https://github.com/kislyuk/yq (
pip install yq
)
详情
我有这个 bash 功能:
function replace_image_repo() {
echo "nexus.local/"
}
在另一边,我有一个 YAML 文件:
# pod.yaml
kind: Pod
# ...
spec:
containers:
- name: web
image: nginx
- name: logger
image: abdennour/logger
我可以用静态值替换 .image
键的所有值:
yq -y '(.. | .image?) |= "mynewimage"' pod.yaml
结果如预期:
# pod.yaml
kind: Pod
# ...
spec:
containers:
- name: web
image: mynewimage # <-- Replacement done successfully
- name: logger
image: mynewimage # <-- Replacement done successfully
但是,我想利用 replace_image_repo
上面的 bash 函数并调用它来 根据当前值计算每次出现的新值 :
例如,nginx
必须替换为 $(replace_image_repo nginx)
的输出,即 nexus.local/nginx
.
是否可以匹配当前值?
如果是这样,是否可以调用 Bash 函数“yq -y '.... $(HERE)'”?
你可以做得更好。由于 https://github.com/kislyuk/yq 利用了下面 jq
的强大功能,您可以使用后者的 --arg
字段来传递要替换的值。例如您的案例可以定制为传递旧的和新的替换字符串。
此外 jq
过滤器表达式 (.. | .image?) |= "mynewimage"
不是最好的方法,因为 ..
使用 recursive descent parsing,你可能最终得到 null
值在您修改后的结果中。正确的方法是修改过滤器以匹配包含字符串的确切对象并替换为目标值。
建议从 shell 函数中删除非标准关键字 function
,尤其是。 bash
replace_image_repo() {
printf '%s' "nexus.local/"
}
并将yq
用作
yq -y --arg old "nginx" \
--arg new "$(replace_image_repo "nginx")" \
'.spec.containers |= map( select(.image == $old).image = $new )' yaml
或者如果您的要求是将替换应用于容器下的所有 .image
字段,您可以在不使用 shell 函数的情况下执行以下操作。
yq -y '.spec.containers |= map(.image = "nexus.local/\(.image)")' yaml
您可以通过将前缀字符串作为参数传递来进一步自定义它
yq -y --arg prefix "nexus.local/" '.spec.containers |= map(.image = ($prefix + "\(.image)") )' yaml
考虑到您关于必须使用非常复杂的 shell 函数的争论,您可以采用以下方法。两者首先根据 shell 函数(复杂,现在抽象)在 YAML 上解析以获取新的图像名称,然后重新使用结果替换原始文件上的图像名称。
这是因为 jq
还不允许在其表达式上下文中执行任意 shell 函数。
#!/usr/bin/env bash
replace_image_repo() {
printf '%s' "nexus.local/"
}
convert_to_array() {
local results=()
while IFS= read -r image; do
results+=( \"$(replace_image_repo "$image")\" )
done < <(yq -r '.spec.containers[].image' yaml)
local IFS=","
printf '[%s]' "${results[*]}"
}
yq -y --argjson images "$(convert_to_array)" \
'reduce range(0; $images | length) as $i (.;
.spec.containers[$i].image = $images[$i])' yaml
概览
- 类似于Substitution with sed + bash function
但是使用
yq
- yq of kislyuk 而不是其他 yq 项目 https://github.com/kislyuk/yq (
pip install yq
)
详情
我有这个 bash 功能:
function replace_image_repo() {
echo "nexus.local/"
}
在另一边,我有一个 YAML 文件:
# pod.yaml
kind: Pod
# ...
spec:
containers:
- name: web
image: nginx
- name: logger
image: abdennour/logger
我可以用静态值替换 .image
键的所有值:
yq -y '(.. | .image?) |= "mynewimage"' pod.yaml
结果如预期:
# pod.yaml
kind: Pod
# ...
spec:
containers:
- name: web
image: mynewimage # <-- Replacement done successfully
- name: logger
image: mynewimage # <-- Replacement done successfully
但是,我想利用 replace_image_repo
上面的 bash 函数并调用它来 根据当前值计算每次出现的新值 :
例如,
nginx
必须替换为$(replace_image_repo nginx)
的输出,即nexus.local/nginx
.是否可以匹配当前值?
如果是这样,是否可以调用 Bash 函数“yq -y '.... $(HERE)'”?
你可以做得更好。由于 https://github.com/kislyuk/yq 利用了下面 jq
的强大功能,您可以使用后者的 --arg
字段来传递要替换的值。例如您的案例可以定制为传递旧的和新的替换字符串。
此外 jq
过滤器表达式 (.. | .image?) |= "mynewimage"
不是最好的方法,因为 ..
使用 recursive descent parsing,你可能最终得到 null
值在您修改后的结果中。正确的方法是修改过滤器以匹配包含字符串的确切对象并替换为目标值。
建议从 shell 函数中删除非标准关键字 function
,尤其是。 bash
replace_image_repo() {
printf '%s' "nexus.local/"
}
并将yq
用作
yq -y --arg old "nginx" \
--arg new "$(replace_image_repo "nginx")" \
'.spec.containers |= map( select(.image == $old).image = $new )' yaml
或者如果您的要求是将替换应用于容器下的所有 .image
字段,您可以在不使用 shell 函数的情况下执行以下操作。
yq -y '.spec.containers |= map(.image = "nexus.local/\(.image)")' yaml
您可以通过将前缀字符串作为参数传递来进一步自定义它
yq -y --arg prefix "nexus.local/" '.spec.containers |= map(.image = ($prefix + "\(.image)") )' yaml
考虑到您关于必须使用非常复杂的 shell 函数的争论,您可以采用以下方法。两者首先根据 shell 函数(复杂,现在抽象)在 YAML 上解析以获取新的图像名称,然后重新使用结果替换原始文件上的图像名称。
这是因为 jq
还不允许在其表达式上下文中执行任意 shell 函数。
#!/usr/bin/env bash
replace_image_repo() {
printf '%s' "nexus.local/"
}
convert_to_array() {
local results=()
while IFS= read -r image; do
results+=( \"$(replace_image_repo "$image")\" )
done < <(yq -r '.spec.containers[].image' yaml)
local IFS=","
printf '[%s]' "${results[*]}"
}
yq -y --argjson images "$(convert_to_array)" \
'reduce range(0; $images | length) as $i (.;
.spec.containers[$i].image = $images[$i])' yaml