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

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

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

问题

以下是您要求的翻译:

  1. 我希望我能使用 yq 递归地迭代一个 YAML,找到所有键值对,其键是“image”,值的类型是“string”(!!str),然后在原始值前添加一个前缀。
  2. 输入:
  3. ``` yaml
  4. serving:
  5. template:
  6. image: "docker.io/serving"
  7. custom:
  8. template:
  9. image:
  10. type: string
  11. description: "..."
  12. eventing:
  13. image: "docker.io/eventing"

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

预期输出:

  1. serving:
  2. template:
  3. image: "private.io/docker.io/serving"
  4. custom:
  5. template:
  6. image:
  7. type: string
  8. description: "..."
  9. eventing:
  10. image: "private.io/docker.io/eventing"

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

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

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

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

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

  1. serving:
  2. template:
  3. image: "private.io/docker.io/serving"
  4. custom:
  5. template:
  6. image:
  7. type: string
  8. description: "..."
  9. eventing:
  10. image: "private.io/docker.io/eventing"
  11. template:
  12. image: "private.io/docker.io/serving"
  13. image: "private.io/docker.io/serving"
  14. private.io/docker.io/serving
  15. template:
  16. image:
  17. type: string
  18. description: "..."
  19. image:
  20. type: string
  21. description: "..."
  22. type: string
  23. description: "..."
  24. string
  25. ...
  26. image: "private.io/docker.io/eventing"
  27. 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:

  1. serving:
  2. template:
  3. image: "docker.io/serving"
  4. custom:
  5. template:
  6. image:
  7. type: string
  8. description: "..."
  9. eventing:
  10. image: "docker.io/eventing"

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

Expected output:

  1. serving:
  2. template:
  3. image: "private.io/docker.io/serving"
  4. custom:
  5. template:
  6. image:
  7. type: string
  8. description: "..."
  9. eventing:
  10. image: "private.io/docker.io/eventing"

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

  1. 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

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

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

  1. serving:
  2. template:
  3. image: "private.io/docker.io/serving"
  4. custom:
  5. template:
  6. image:
  7. type: string
  8. description: "..."
  9. eventing:
  10. image: "private.io/docker.io/eventing"
  11. template:
  12. image: "private.io/docker.io/serving"
  13. image: "private.io/docker.io/serving"
  14. private.io/docker.io/serving
  15. template:
  16. image:
  17. type: string
  18. description: "..."
  19. image:
  20. type: string
  21. description: "..."
  22. type: string
  23. description: "..."
  24. string
  25. ...
  26. image: "private.io/docker.io/eventing"
  27. private.io/docker.io/eventing

Any ideas or walk around ? Thanks, sincerely~

答案1

得分: 1

  1. 有的,你差不多就快做到了。只需在括号内保留上下文:
  2. yq '(.. | select(key == "image" and type == "!!str")) |= "private.io/" + .'
  1. serving:
  2. template:
  3. image: "private.io/docker.io/serving"
  4. custom:
  5. template:
  6. image:
  7. type: string
  8. description: "..."
  9. eventing:
  10. image: "private.io/docker.io/eventing"

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


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

  1. yq -y 'walk(
  2. if type == "object" and has("image") and (.image|type) == "string"
  3. then .image |= "private.io/" + . else . end
  4. )'
  5. # 或者
  6. gojq --yaml-input --yaml-output 'walk(
  7. if type == "object" and has("image") and (.image|type) == "string"
  8. then .image |= "private.io/" + . else . end
  9. )'
英文:

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

  1. yq '(.. | select(key == "image" and type == "!!str")) |= "private.io/" + .'
  1. serving:
  2. template:
  3. image: "private.io/docker.io/serving"
  4. custom:
  5. template:
  6. image:
  7. type: string
  8. description: "..."
  9. eventing:
  10. 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.

  1. yq -y 'walk(
  2. if type == "object" and has("image") and (.image|type) == "string"
  3. then .image |= "private.io/" + . else . end
  4. )'
  5. # or
  6. gojq --yaml-input --yaml-output 'walk(
  7. if type == "object" and has("image") and (.image|type) == "string"
  8. then .image |= "private.io/" + . else . end
  9. )'

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:

确定