如何根据键和值类型在 yq 中递归替换值?

huangapple go评论60阅读模式
英文:

How to replace value recursively in yq depend on key and value type?

问题

以下是您要求的翻译:

我希望我能使用 yq 递归地迭代一个 YAML,找到所有键值对,其键是“image”,值的类型是“string”(!!str),然后在原始值前添加一个前缀。

输入:
``` yaml
serving:
  template:
    image: "docker.io/serving"
custom:
  template:
    image: 
      type: string
      description: "..."
eventing:
  image: "docker.io/eventing"

如果其值的类型递归为string(!!str),则将前缀private.io/添加到所有image字段。

预期输出:

serving:
  template:
    image: "private.io/docker.io/serving"
custom:
  template:
    image: 
      type: string
      description: "..."
eventing:
  image: "private.io/docker.io/eventing"

对于等效的 JSON,我可以使用walk运算符来执行这样的操作:

jq 'walk(if type == "object" and has("image") and (.image|type) == "string" then .image = "private.io/" + .image else . end)' input.json

是否有类似walk的等效运算符,我已经尝试了..运算符:

yq '.. | select(tag == "!!str" and key == "image") |= "private.io/" + . ' input.json

但是这个命令会向 YAML 中添加一些条目,导致:

serving:
  template:
    image: "private.io/docker.io/serving"
custom:
  template:
    image:
      type: string
      description: "..."
eventing:
  image: "private.io/docker.io/eventing"
template:
  image: "private.io/docker.io/serving"
image: "private.io/docker.io/serving"
private.io/docker.io/serving
template:
  image:
    type: string
    description: "..."
image:
  type: string
  description: "..."
type: string
description: "..."
string
...
image: "private.io/docker.io/eventing"
private.io/docker.io/eventing

有没有任何想法或解决方法?谢谢,真诚的~

英文:

I wish I could use yq to iterate a yaml recursively, find all key-value pairs, whose key is image and value type is string(!!str), then add a prefix to the original value.

Input:

serving:
  template:
    image: "docker.io/serving"
custom:
  template:
    image: 
      type: string
      description: "..."
eventing:
  image: "docker.io/eventing"

Add a prefix private.io/ to all image field if its value type is string(!!str) recursively.

Expected output:

serving:
  template:
    image: "private.io/docker.io/serving"
custom:
  template:
    image: 
      type: string
      description: "..."
eventing:
  image: "private.io/docker.io/eventing"

For a equivalent json, I can use the walk operator to do such thing:

jq 'walk(if type == "object" and has("image") and (.image|type) == "string" then .image = "private.io/" + .image else . end)' input.json

Is there any equivalent operator like walk, I have tried the .. operator

yq '.. | select(tag == "!!str" and key == "image") |= "private.io/" + . ' input.json

But this command add some entries to the yaml, result in:

serving:
  template:
    image: "private.io/docker.io/serving"
custom:
  template:
    image:
      type: string
      description: "..."
eventing:
  image: "private.io/docker.io/eventing"
template:
  image: "private.io/docker.io/serving"
image: "private.io/docker.io/serving"
private.io/docker.io/serving
template:
  image:
    type: string
    description: "..."
image:
  type: string
  description: "..."
type: string
description: "..."
string
...
image: "private.io/docker.io/eventing"
private.io/docker.io/eventing

Any ideas or walk around ? Thanks, sincerely~

答案1

得分: 1

有的,你差不多就快做到了。只需在括号内保留上下文:

yq '(.. | select(key == "image" and type == "!!str")) |= "private.io/" + .'
serving:
  template:
    image: "private.io/docker.io/serving"
custom:
  template:
    image:
      type: string
      description: "..."
eventing:
  image: "private.io/docker.io/eventing"

已在 mikefarah/yq v4.31.1 上进行测试


注意:使用 kislyuk/yqitchyny/gojq 你也可以在你的 YAML 输入上使用原始的 walk 过滤器。这两个工具都可以使用正确的 jq 语法处理 YAML 文件。

yq -y 'walk(
  if type == "object" and has("image") and (.image|type) == "string" 
  then .image |= "private.io/" + . else . end
)'

# 或者

gojq --yaml-input --yaml-output 'walk(
  if type == "object" and has("image") and (.image|type) == "string" 
  then .image |= "private.io/" + . else . end
)'
英文:

There is, and you almost had it. Just set parentheses to retain the context:

yq '(.. | select(key == "image" and type == "!!str")) |= "private.io/" + .'
serving:
  template:
    image: "private.io/docker.io/serving"
custom:
  template:
    image:
      type: string
      description: "..."
eventing:
  image: "private.io/docker.io/eventing"

Tested with mikefarah/yq v4.31.1


Note: With kislyuk/yq or itchyny/gojq you can also use your original walk filter on your YAML input. Both tools can process YAML files using proper jq syntax.

yq -y 'walk(
  if type == "object" and has("image") and (.image|type) == "string" 
  then .image |= "private.io/" + . else . end
)'

# or

gojq --yaml-input --yaml-output 'walk(
  if type == "object" and has("image") and (.image|type) == "string" 
  then .image |= "private.io/" + . else . end
)'

huangapple
  • 本文由 发表于 2023年4月17日 13:59:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76032079.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定