1

概述

细节

我有这个 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

但是,我想利用上面的 bash 函数replace_image_repo并调用它来根据当前值计算每次出现的新值

  • 例如,nginx必须替换为$(replace_image_repo nginx)应该是的输出nexus.local/nginx

  • 是否可以匹配当前值?

  • 如果是这样,是否可以调用 Bash 函数“yq -y '.... $(HERE)'”?

4

1 回答 1

2

你可以做得比这更好。由于https://github.com/kislyuk/yq利用了底层的强大jq功能,您可以使用后者的--arg字段来传递您想要替换的值。例如,可以自定义您的案例以传递要传递的旧的和新的替换字符串。

jq过滤器表达式(.. | .image?) |= "mynewimage"也不是最好的方法,因为使用..递归下降解析,您最终可能会null在修改后的结果中得到值。正确的方法是修改过滤器以匹配包含字符串的确切对象并替换为目标值。

function建议从 shell 函数 esp 中删除非标准关键字。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
于 2020-07-29T11:27:14.247 回答