yq
# yq 实用指南
命令行里的 YAML/JSON/XML 处理器,语法对标 jq,专为配置文件读写、批量修改、格式转换而生。
本文档基于 mikefarah/yq v4(Go 版,目前主流)。Python 版 kislyuk/yq 是 jq 包装器,语法不同,请注意区分。
安装:brew install yq,验证 yq --version。
# 基础读取
yq '.' file.yaml # 读取整个文件(格式化输出)
yq '.metadata.name' deploy.yaml # 读取嵌套字段
yq '.spec.replicas' deploy.yaml # 读取数值
yq '.spec.template.containers[0].name' deploy.yaml # 数组下标访问
yq '.spec.containers[].name' deploy.yaml # 遍历数组,逐个输出
yq '.spec.containers[0].ports[].containerPort' deploy.yaml # 嵌套数组展开
1
2
3
4
5
6
2
3
4
5
6
带路径前缀输出(方便知道值来自哪):
yq -o=props '.' file.yaml # 输出 key=value 扁平格式
yq '... | style=""' file.yaml # 递归遍历所有节点
1
2
2
读取时处理不存在的字段:
yq '.metadata.namespace // "default"' deploy.yaml # 字段不存在时给默认值
1
# 输出格式控制
yq 支持多种输入输出格式,用 -P(输入)和 -o(输出)指定。
| 格式 | 输入 flag | 输出 flag | 说明 |
|---|---|---|---|
| YAML | 默认 | 默认 | 保留注释和顺序 |
| JSON | -P 或自动识别 | -o=json | 紧凑或美化 |
| XML | -P=xml | -o=xml | 支持属性 |
| props | -P=props | -o=props | Java properties 风格 |
| csv / tsv | 自动 | -o=csv | 数组转表格 |
# YAML 转 JSON(最常用)
yq -o=json '.' file.yaml
yq -o=json -I=2 '.' file.yaml # JSON 缩进 2 空格
# JSON 转 YAML
yq -P '.' file.json # -P 表示输入是 JSON(也可自动识别)
yq '.' file.json # 多数版本自动识别输入格式
# 紧凑 JSON(单行)
yq -o=json -I=0 '.' file.yaml
# YAML 转 properties
yq -o=props '.' file.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
颜色输出:默认终端着色,管道输出时自动关闭。强制着色 yq -C,关闭 yq -M。
# 修改与写入
# 赋值操作
# 修改字段值(输出到 stdout,不改变原文件)
yq '.spec.replicas = 5' deploy.yaml
# 原地修改文件(最常用)
yq -i '.spec.replicas = 5' deploy.yaml
# 新增字段
yq -i '.metadata.labels.env = "prod"' deploy.yaml
# 嵌套新增(中间路径自动创建)
yq -i '.spec.template.metadata.annotations."sidecar.istio.io/inject" = "true"' deploy.yaml
# 删除字段
yq -i 'del(.metadata.labels.temp)' deploy.yaml
# 删除数组元素
yq -i 'del(.spec.containers[1])' deploy.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 基于旧值计算
yq -i '.spec.replicas += 1' deploy.yaml # 加 1
yq -i '.metadata.name = .metadata.name + "-canary"' deploy.yaml # 字符串拼接
yq -i '.spec.replicas = .spec.replicas * 2' deploy.yaml # 乘 2
1
2
3
2
3
# 多字段同时修改
yq -i '
.metadata.labels.app = "nginx" |
.spec.replicas = 3 |
.spec.template.spec.containers[0].image = "nginx:1.25"
' deploy.yaml
1
2
3
4
5
2
3
4
5
用 | 连接多个操作,等价于顺序执行。
# 数组操作
# 遍历与过滤
# 遍历数组所有元素
yq '.items[]' list.yaml
# 过滤:选出 status=Running 的 Pod
yq '.items[] | select(.status.phase == "Running")' pods.yaml
# 过滤后只取名字
yq '.items[] | select(.status.phase == "Running") | .metadata.name' pods.yaml
# 多条件过滤
yq '.items[] | select(.status.phase == "Running" and .metadata.namespace == "default")' pods.yaml
# 过滤后保留数组结构(加括号)
yq '[.items[] | select(.status.phase == "Running")]' pods.yaml # 输出仍是数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 映射与转换
# 从数组中提取字段组成新数组
yq '[.items[].metadata.name]' pods.yaml # 输出 ["pod1","pod2",...]
yq -o=csv '.items[] | [.metadata.name, .status.phase]' pods.yaml # 转 CSV
# 对每个元素做转换
yq '.spec.containers[] |= . + {resources: {limits: {cpu: "500m"}}}' deploy.yaml
1
2
3
4
5
6
2
3
4
5
6
# 排序与去重
yq '.items | sort_by(.metadata.name)' list.yaml # 按名字排序
yq '.items | sort_by(.creationTimestamp) | reverse' list.yaml # 按时间倒序
yq '.tags | unique' file.yaml # 数组去重
yq '.items | length' list.yaml # 数组长度
1
2
3
4
2
3
4
# 多文件操作
# 合并文件
yq 的合并用 * 操作符,支持不同合并策略。
# 基础合并:第二个文件覆盖第一个(同字段覆盖,不同字段保留)
yq '. * load("override.yaml")' base.yaml
# 深度合并(递归合并嵌套对象,数组默认替换)
yq '. *d load("override.yaml")' base.yaml # *d = deep merge
# 数组合并(追加而非替换)
yq '. *+ load("extra.yaml")' base.yaml # *+ = 数组追加
# 合并后输出到新文件
yq '. * load("prod.yaml")' base.yaml > merged.yaml
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
合并策略速查:
| 操作符 | 对象 | 数组 | 说明 |
|---|---|---|---|
* | 覆盖 | 替换 | 默认 |
*d | 深度合并 | 替换 | 递归合并嵌套 |
*+ | 覆盖 | 追加 | 数组尾部追加 |
*d+ | 深度合并 | 追加 | 最常用的"友好合并" |
# 对比与引用
# 引用另一个文件的值进行赋值
yq -i '.spec.replicas = load("config.yaml").replicas' deploy.yaml
# 从文件读取字符串值
yq '.message = load_str("notes.txt")' file.yaml
# 多文件输入,按索引引用
yq 'select(fileIndex == 0)' a.yaml b.yaml # 只处理第一个文件
yq 'select(fileIndex == 1) | .metadata.name' a.yaml b.yaml
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 注释与高级特性
yq v4 的核心优势是保留 YAML 注释和格式,这是 jq 做不到的。
# 读取注释
yq '.metadata headComment' file.yaml # 字段上方的注释
yq '.metadata lineComment' file.yaml # 行尾注释
yq '.metadata footComment' file.yaml # 字段下方注释
# 添加/修改注释
yq -i '.metadata headComment = "应用元数据"' file.yaml
yq -i '.spec.replicas lineComment = "副本数"' file.yaml
# 删除注释
yq -i '.metadata headComment = ""' file.yaml
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
锚点与别名:
yq 'explode(.)' file.yaml # 展开所有锚点引用(&/* → 实际值)
1
多行字符串样式控制:
yq '.description style="literal"' file.yaml # 用 | 块样式
yq '.description style="folded"' file.yaml # 用 > 折叠样式
yq '.description style=""' file.yaml # 自动选择
1
2
3
2
3
# 实战场景
# Kubernetes 配置批量处理
# 查看所有 Pod 名字和状态
kubectl get pods -o yaml | yq '.items[] | [.metadata.name, .status.phase] | @csv'
# 批量给所有 deployment 加标签
for f in deploy/*.yaml; do yq -i '.metadata.labels.managed-by = "argo"' "$f"; done
# 提取所有容器镜像
yq '[.. | select(has("image")) | .image] | unique' deploy.yaml
# 修改所有容器的镜像 tag
yq -i '(.spec.template.spec.containers[] | select(.name == "app").image) |= sub(":.*", ":v2.1.0")' deploy.yaml
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 配置文件转换
# Helm values 转 JSON 给其他工具用
yq -o=json '.' values.yaml > values.json
# JSON 转 YAML 并格式化
yq -P '.' config.json > config.yaml
# 提取嵌套配置为扁平 key=value
yq -o=props '.' application.yaml > application.properties
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# CI/CD 中动态修改
# 用环境变量替换镜像 tag
yq -i ".spec.template.spec.containers[0].image = \"myapp:${TAG}\"" deploy.yaml
# 条件修改:只有 replicas > 3 时才设为 3
yq -i 'select(.spec.replicas > 3) | .spec.replicas = 3' deploy.yaml
1
2
3
4
5
2
3
4
5
# 与 jq 的区别
| 特性 | yq | jq |
|---|---|---|
| 原生格式 | YAML | JSON |
| 注释保留 | 支持 | 不支持 |
| 输出 YAML | 原生 | 需额外工具 |
| 语法 | 类 jq,扩展了 YAML 特性 | 标准 jq |
| 多格式输入输出 | YAML/JSON/XML/CSV/props | JSON |
| 原地修改 | -i | 不支持(需重定向) |
混用技巧:yq 转 JSON 后管道给 jq 做复杂计算,再转回 YAML:
yq -o=json '.' file.yaml | jq '.items | map(select(.price > 10))' | yq -P '.'
1
# 常用技巧
- 不记得语法:
yq --help或man yq,v4 文档在 https://mikefarah.gitbook.io/yq/ - 预览不修改:去掉
-i,先看输出确认无误再加-i原地写 - 复杂表达式写文件:
yq -f script.yq file.yaml,把表达式存成文件避免 shell 转义噩梦 - 调试表达式:
yq -v输出详细日志,或分步拆表达式确认每一步结果 - 处理大文件:yq 一次性加载到内存,GB 级文件建议用
yq '.'流式或换工具 - shell 变量传入:用双引号包裹表达式,
yq ".field = \"$VAR\"",或用env(VAR)函数:yq '.field = env(MY_VAR)' file.yaml
# 常见问题
Error: cannot index array with 'name':在数组上用了对象访问,先[]展开或加[0]。- 修改后注释丢了:确认用的是 mikefarah/yq v4,Python 版 yq 不保留注释。
-i不生效:v3 用-y -i,v4 直接-i;检查版本yq --version。- 数字被改成字符串:赋值时不加引号
.replicas = 3是数字,加引号.replicas = "3"是字符串。 - 布尔值问题:YAML 中
true/false是布尔,"true"是字符串;yq 赋值时.flag = true保持布尔类型。 - key 含特殊字符:用引号包裹
.metadata.annotations."app.kubernetes.io/name"。
# 链接
上次更新: 2026/09/10, 14:32:04