yq —— YAML / JSON / XML 的 jq
yq —— YAML / JSON / XML 的 jq
分类:04 文本处理 适用:全平台。注意有两个同名工具,语法不兼容 一句话:改 K8s 清单、Ansible 变量、CI 配置,比
sed安全,比手改可靠。
1. 先确认你装的是哪个 yq
yq --version
| 版本 | 特征 | 语法 |
|---|---|---|
| mikefarah/yq(Go,v4) | 输出含 mikefarah/yq |
yq '.a.b' file.yml(类 jq) |
| kislyuk/yq(Python) | 输出 yq 3.x(基于 PyYAML) |
yq -y '.a.b'(需 -y 输出 YAML) |
本文以 mikefarah v4 为准(当前主流,单二进制,无依赖)。装错版本会出现"命令照着敲却报错"。
# 安装 v4
curl -L https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o /usr/local/bin/yq
chmod +x /usr/local/bin/yq
# 或
apt install -y yq # 注意部分仓库是老版本
brew install yq
2. 基础
yq '.a.b' file.yml # 读取(输出 YAML)
yq -r '.a.b' file.yml # 原始字符串(无引号)
yq -o=json '.' file.yml # YAML → JSON
yq -P '.' file.json # JSON → YAML
yq '.items[0].name' file.yml
yq '.spec.containers[].image' deploy.yml
yq '.[]' list.yml # 展开数组
yq 'keys' file.yml
yq 'length' file.yml
yq '.a | .b' file.yml # 管道
原地修改
yq -i '.replicas = 3' deploy.yml # -i 直接写回
yq -i '.image = "app:1.2.3"' deploy.yml
yq -i 'del(.metadata.annotations)' deploy.yml
yq -i '.spec.template.spec.containers[0].image |= sub(":.*"; ":1.2.3")' deploy.yml
-i 前先复制或 git diff,YAML 的缩进/注释处理在不同版本有差异。
3. 常用操作
读
yq '.metadata.name' k8s.yml
yq '.spec.template.spec.containers[].image' k8s.yml
yq '.data | keys' cm.yml
yq '.items[] | select(.kind == "Deployment") | .metadata.name' all.yml
yq '.[] | select(.enabled == true)' list.yml
yq '.env[] | select(.name == "DB_HOST") | .value' deploy.yml
改
yq -i '.a.b = "x"' f.yml # 赋值
yq -i '.a.b |= . + 1' f.yml # 基于原值修改
yq -i '.a.b += ["new"]' f.yml # 数组追加
yq -i '.spec.replicas = 5' f.yml
yq -i '(.spec.template.spec.containers[] | select(.name == "app") | .image) = "app:2.0"' f.yml
yq -i 'del(.status)' f.yml
yq -i '.metadata.labels.team = "infra"' f.yml
yq -i '.spec.template.metadata.annotations."prometheus.io/scrape" = "true"' f.yml
合并
yq '.a * .b' a.yml b.yml # 深合并(后者覆盖前者)
yq ea '. as $item ireduce ({}; . * $item)' a.yml b.yml # 多文档合并
yq -s '.' a.yml b.yml # 合成数组
多文档(--- 分隔)
yq -N '.kind' multi.yml # 每个文档都取
yq 'select(.kind == "Service")' multi.yml
yq -i 'select(.kind == "Deployment") | .spec.replicas = 2' multi.yml
yq ea '[.] | length' multi.yml # 文档数
4. 输出控制
yq -o=json '.' f.yml # 转 JSON
yq -o=props '.' f.yml # properties
yq -o=xml '.' f.xml # XML 输出
yq -P '.' f.json # 强制 YAML 输出
yq -r '.a' f.yml # 无引号
yq -j '.' f.yml # 紧凑 JSON(无缩进)
yq -I4 '.' f.yml # 缩进 4 空格
yq '.. f.yml # 流式风格
yq -e '.a == "x"' f.yml # 断言,false 时退出码 1(CI 用)
5. 变量与 env
yq '.image = strenv(IMAGE_TAG)' deploy.yml # 读环境变量
yq --arg v "1.2.3" '.image = "app:" + $v' deploy.yml
yq --argjson r 3 '.replicas = $r' deploy.yml
CI 里非常实用:
IMAGE_TAG="$CI_COMMIT_SHA" yq -i '.spec.template.spec.containers[0].image = "registry/app:" + strenv(IMAGE_TAG)' deploy.yml
6. 实战场景
6.1 批量改 K8s 镜像版本(发布脚本)
#!/bin/bash
set -euo pipefail
NEW_TAG="$1"
for f in k8s/*.yaml; do
yq -i '(.spec.template.spec.containers[] | select(.name == "app") | .image) |= sub(":[^:]+$"; ":'"$NEW_TAG"'")' "$f"
done
kubectl diff -f k8s/ || true
6.2 从 compose 文件提取所有镜像
yq -r '.services[].image' docker-compose.yml | sort -u
6.3 检查 K8s 清单是否都设置了 resources
yq -e 'select(.kind == "Deployment") | .spec.template.spec.containers[] | has("resources")' deploy.yml
6.4 YAML ↔ JSON 互转
yq -o=json '.' config.yml > config.json
yq -P '.' config.json > config.yml
6.5 修改 Ansible 变量
yq -i '.nginx_port = 8080' group_vars/all.yml
yq -i '.packages += ["htop"]' group_vars/all.yml
6.6 对比两个 YAML 的差异(转成规范 JSON 再 diff)
diff <(yq -o=json -P '.' a.yml) <(yq -o=json -P '.' b.yml)
7. 常见坑
- 装成了 kislyuk 版:
yq '.a' f.yml会输出 JSON 而不是 YAML,需要-y。先yq --version确认。 -i会重排格式:注释、空行、引号风格可能变化,重要文件先git diff。- 锚点与别名(
&/*):v4 默认展开,需要--tag '!!merge'或explode(.)处理合并键。 - 键名含特殊字符:
.metadata.annotations."prometheus.io/scrape"必须加引号。 - 数字被当字符串:
"8080"与8080不同,K8s 里类型错会导致 apply 失败,用--argjson。 - 布尔值大小写:YAML 1.1 里
yes/no/on/off也算布尔,v4 按 1.2 处理,可能与旧配置不一致。 - 多文档不加
-N会报错:yq '.a' multi.yml只处理第一个文档,要遍历用yq ea或-N。 select后赋值不生效:必须用括号包住整个路径(... | select(...)) = x。-i与管道 stdin 混用:cat f | yq -i ...会失败,-i只接受文件参数。- XML 支持有限:属性用
+@attr访问,复杂 XML 用xmlstarlet。 - 大文件性能:v4 全量加载,几十 MB 的 YAML 会慢,尽量避免。
8. 速查表
yq --version # 先确认版本
yq '.a.b' f.yml # 读
yq -r '.a.b' f.yml # 裸字符串
yq -i '.a.b = "x"' f.yml # 原地改
yq -i 'del(.a)' f.yml # 删
yq -i '.list += ["x"]' f.yml # 数组追加
yq '.items[] | select(.k == "v")' f.yml # 过滤
yq -o=json '.' f.yml # 转 JSON
yq -P '.' f.json # 转 YAML
yq -N '.kind' multi.yml # 多文档
yq --arg v x '.a = $v' f.yml # 变量
yq '.a = strenv(ENV)' f.yml # 环境变量
yq -e '.a == 1' f.yml # CI 断言
yq '.a * .b' a.yml b.yml # 深合并