yq
pip install yq
)我有这个bash功能:
function replace_image_repo() {
echo "nexus.local/${1}"
}
另一方面,我有一个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)'”?
答案 0 :(得分:1)
您可以做得更好。由于https://github.com/kislyuk/yq利用了下方的jq
的强大功能,因此您可以使用后者的--arg
字段来传递要替换的值。例如您的案例可以自定义为传递旧的和新的替换字符串。
此外,jq
过滤器表达式(.. | .image?) |= "mynewimage"
也不是最好的方法,因为..
使用recursive descent parsing,您可能会在自己的代码中得到null
个值修改结果。正确的方法是修改过滤器以匹配包含字符串的确切对象,并替换为目标值。
建议从shell函数esp中删除非标准关键字function
。 bash
replace_image_repo() {
printf '%s' "nexus.local/${1}"
}
并使用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函数的争论,您可以执行以下方法。在YAML上的两次解析首先基于shell函数(复杂,现在已抽象)获取新的图像名称,然后再使用结果将原始文件中的图像名称替换回原处。
这是因为jq
尚不允许在其表达式上下文中执行任意shell函数。
#!/usr/bin/env bash
replace_image_repo() {
printf '%s' "nexus.local/${1}"
}
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