yq Style 操作符完全指南:读取与设置 YAML 节点样式(引号、标签、Flow 与多行块)
【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq
导读
yq是跨平台的命令行数据文件处理器,支持 YAML、JSON、XML、CSV、TOML、HCL 与 properties 等多种格式。本文聚焦style操作符——它用于读取或设置节点的样式(字符串引号样式、YAML 标签样式、flow/block 样式等),从而精细控制文档的 YAML 格式化输出。阅读完本文,你将掌握如何为单个节点或整棵文档树批量设置 double/single/literal/folded/flow/tagged 等样式、如何通过style |= .相对赋值、如何读取已有样式,以及-P/--prettyPrint标志与style=""之间的等价关系。
本文的实操命令与示例均可直接复制运行;底层原理部分结合 pkg/yqlib/operator_style.go、pkg/yqlib/candidate_node.go、pkg/yqlib/lib.go 等源码给出证据。
一、认识 style 操作符
style是 yq 中一个可赋值(assignable)的二元操作符,同时具备读取与写入两种形态:
- 读取:
yq '.. | style' file.yml,输出每个匹配节点的当前样式名; - 写入:
yq '.. style="double"' file.yml,把匹配到的节点样式批量设置为目标样式。
从 pkg/yqlib/operation.go 可以看出它对应两个底层操作:
ASSIGN_STYLE(优先级 40,处理器assignStyleOperator),负责写入样式;GET_STYLE(优先级 50,处理器getStyleOperator),负责读出样式。
词法层面,pkg/yqlib/lexer_participle.go 将style注册为可赋值操作符(assignableOp("style", getStyleOpType, assignStyleOpType)),因此它既可以单独求值(读取),也可以出现在style="..."或style |= ...这类赋值表达式中。
在源码内部,样式被建模为一个位掩码类型Style(pkg/yqlib/candidate_node.go):
type Style uint32 const ( TaggedStyle Style = 1 << iota DoubleQuotedStyle SingleQuotedStyle LiteralStyle FoldedStyle FlowStyle )CandidateNode结构体(pkg/yqlib/candidate_node.go)通过Style Style字段保存节点样式,打印与编码时据此决定 YAML 输出格式。之所以采用位掩码,是为了让一个节点可以同时携带多个样式位(例如 tagged 与 double 组合),String()方法(pkg/yqlib/candidate_node.go)会逐个拼接出如TaggedStyle、DoubleQuotedStyle这样的可读名称。
二、支持的样式值一览
写入样式时,字符串会被 pkg/yqlib/operator_style.go 中的parseStyle函数解析为对应的Style常量;空字符串表示清除样式(回到默认样式);任何未识别的样式名都会直接报错unknown style <value>。
| 样式字符串 | 对应常量 | 效果(YAML 输出形态) |
|---|---|---|
"tagged" | TaggedStyle | 显式输出!!str、!!int、!!bool、!!map、!!seq等标签 |
"double" | DoubleQuotedStyle | 标量使用双引号"..." |
"single" | SingleQuotedStyle | 标量使用单引号'...' |
"literal" | LiteralStyle | 标量使用字面块\|-(多行块,保留换行) |
"folded" | FoldedStyle | 标量使用折叠块>-(多行块,换行折叠为空格) |
"flow" | FlowStyle | 映射与序列输出为 flow 风格{...}/[...] |
""(空串) | 0 | 重置为默认样式(等价于 pretty print) |
| 其他值 | - | 报错unknown style <value> |
样式在读取(解析)侧同样有对应映射:pkg/yqlib/candidate_node_goccy_yaml.go 在解析 YAML 时识别单/双引号、literal、folded、flow 等形态并写入Style字段;使用 go-yaml 时则通过 pkg/yqlib/candidate_node_yaml.go 完成 yaml.Style 与内部 Style 的双向转换。这意味着——你写在源文件里的引号风格,yq 能感知到,也能帮你改写。
三、更新并设置单个节点的样式(简单写法)
给定sample.yml:
a: b: thing c: something先更新值,再把它设置为双引号样式:
yq '.a.b = "new" | .a.b style="double"' sample.yml输出:
a: b: "new" c: something要点:
style="double"是赋值式写法,左侧.a.b定位目标节点,右侧"double"提供样式名;- 管道
|把“更新值”与“设置样式”两步串联起来; - 该场景在 pkg/yqlib/operator_style_test.go 中有对应的自动化测试用例(
Update and set style of a particular node (simple))。
四、使用路径变量设置节点样式
同样的效果,也可以借助with(...)把路径固化为上下文,在块内相对操作:
yq 'with(.a.b ; . = "new" | . style="double")' sample.yml输出:
a: b: "new" c: something这里with(.a.b ; ...)先进入.a.b路径,块内.代表该节点自身;= "new"更新值、. style="double"设置样式。当需要“先定位、后做多步操作”时,这种写法比反复书写完整路径更清晰,对应测试用例见 pkg/yqlib/operator_style_test.go。
五、批量设置 tagged 样式(显式类型标签)
给定包含多种类型的sample.yml:
a: cat b: 5 c: 3.2 e: true f: - 1 - 2 - 3 g: something: cool递归匹配所有节点并加上显式标签:
yq '.. style="tagged"' sample.yml输出:
!!map a: !!str cat b: !!int 5 c: !!float 3.2 e: !!bool true f: !!seq - !!int 1 - !!int 2 - !!int 3 g: !!map something: !!str cool说明:
..是递归下降操作符,遍历文档中所有节点(含根节点);!!map、!!seq表明容器类型,!!str/!!int/!!float/!!bool显式标注标量类型;- 适合需要精确交换类型信息、避免下游推断歧义的场景(例如生成严格类型校验的配置)。
六、设置 double 双引号样式
yq '.. style="double"' sample.yml输出:
a: "cat" b: "5" c: "3.2" e: "true" f: - "1" - "2" - "3" g: something: "cool"注意:所有标量(包括数字与布尔值)都会被双引号包裹,因为 style 只影响输出形态,并不改变节点本身的 tag(类型)。b、c、e的取值仍是字符串形态的数字与布尔字面量,但 YAML 中加了引号后,下游解析器会按字符串对待——这是格式化时需要注意的类型语义变化。
七、设置 double 样式并作用于 map 键(...)
默认..只覆盖节点的值,而 map 的键也同样是节点。若希望键也被双引号包裹,使用三连点...:
yq '... style="double"' sample.yml输出:
"a": "cat" "b": "5" "c": "3.2" "e": "true" "f": - "1" - "2" - "3" "g": "something": "cool"对比上一节:...比..多匹配一层——递归下降时同时命中键节点与值节点,因此键a、b、c、e、g、something也都带上了双引号。这在生成“所有键值都必须引号化”的 YAML(如某些严格 schema 的 CI 配置)时非常实用。
八、设置 single 单引号样式
yq '.. style="single"' sample.yml输出:
a: 'cat' b: '5' c: '3.2' e: 'true' f: - '1' - '2' - '3' g: something: 'cool'单引号样式的输出更接近人工手写习惯,视觉噪音比双引号小;当字符串本身包含双引号而无需转义时,单引号也是 YAML 中更自然的选择。
九、设置 literal 字面块样式
yq '.. style="literal"' sample.yml输出:
a: |- cat b: |- 5 c: |- 3.2 e: |- true f: - |- 1 - |- 2 - |- 3 g: something: |- cool|-是 YAML 字面块指示符(chomping indicator-表示去掉末尾换行)。所有标量都被转换为多行字面块形态。典型应用是:把需要保留原始换行/缩进的文本(如脚本片段、证书、README 摘要)以块形式输出,避免引号转义地狱。
十、设置 folded 折叠块样式
yq '.. style="folded"' sample.yml输出:
a: >- cat b: >- 5 c: >- 3.2 e: >- true f: - >- 1 - >- 2 - >- 3 g: something: >- cool>-是折叠块指示符:块内换行在语义上被折叠为空格,适合书写长段落文本(README 描述、注释性内容),让源文件更易读而取值保持为一行。literal 与 folded 的区别正是保留换行 vs 折叠换行。
十一、设置 flow 样式(单行紧凑输出)
yq '.. style="flow"' sample.yml输出:
{a: cat, b: 5, c: 3.2, e: true, f: [1, 2, 3], g: {something: cool}}flow 样式把整棵文档压成 JSON 风格的紧凑形态:映射用{}、序列用[]。适合:
- 日志单行输出、管道中的紧凑数据交换;
- 需要控制输出体积的 CI 场景;
- 作为中间形态快速人工检查结构。
从源码看,解析器在读取 flow 形态(IsFlowStyle)的映射与序列时也会设置FlowStyle(pkg/yqlib/candidate_node_goccy_yaml.go),因此 flow 样式可以被“感知”并再次重置回块样式。
十二、重置样式(pretty print):style=""与-P/--prettyPrint
设置空字符串样式会清除节点上的所有样式,让文档回到默认(块式、无引号)输出。注意这里必须使用...(连键一起匹配),否则 map 键上残留的引号样式不会被清除。
给定一个“样式混乱”的sample.yml:
{a: cat, "b": 5, 'c': 3.2, "e": true, f: [1,2,3], "g": { something: "cool"} }执行:
yq '... style=""' sample.yml输出:
a: cat b: 5 c: 3.2 e: true f: - 1 - 2 - 3 g: something: coolyq 为此提供了专用短标志。在 cmd/root.go 中:
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print, shorthand for '... style = \"\"'")即yq -P file.yml等价于yq '... style=""' file.yml。需要说明的是,-P的实际展开式略有增强(pkg/yqlib/lib.go):
var PrettyPrintExp = `(... | (select(tag != "!!str"), select(tag == "!!str") | select(test("(?i)^(y|yes|n|no|on|off)$") | not)) ) style=""`展开后的表达式会跳过纯字符串节点,并跳过y/yes/n/no/on/off这类在 YAML 1.1 中可能被误读为布尔的字符串,避免给它们补引号引入歧义。因此:
- 只想“抹掉所有样式”:用
yq '... style=""'; - 想要“安全的默认格式化”:直接
yq -P(或yq --prettyPrint)。
在 cmd/evaluate_sequence_command.go 中可以看到:未传表达式时-P直接使用PrettyPrintExp,传了表达式时则把该表达式追加在管道尾部(expr | PrettyPrintExp)。
十三、用 assign-update 相对设置样式(style |=)
style支持 yq 的|=(assign-update)语法:右侧表达式以每个匹配节点自身为输入求值,再把结果写回其样式。这允许根据节点当前取值/样式动态决定新样式。
给定sample.yml:
a: single b: double执行:
yq '.[] style |= .' sample.yml输出:
a: 'single' b: "double"这里.[]遍历顶层每个值节点,style |= .把节点自身的值(字符串single/double)当作样式名写回该节点,因此a变成单引号、b变成双引号。这个例子巧妙展示了 style 与普通数据流的一致性——样式名本身也是数据,可以被读取、变换、再写回。
从实现上看,pkg/yqlib/operator_style.go 的assignStyleOperator专门处理了UpdateAssign分支(对应|=):对每个匹配节点,以该节点为上下文重新求值 RHS,再把得到的样式应用到candidate.Style。
十四、读取样式(get)
style也可以作为普通的一元操作读取节点当前样式。
给定sample.yml:
{a: "cat", b: 'thing'}执行:
yq '.. | style' sample.yml输出:
flow double single解析:
- 根节点是 flow 风格映射(
{...}),输出flow; a的值"cat"是双引号,输出double;b的值'thing'是单引号,输出single。
实现上,pkg/yqlib/operator_style.go 的getStyleOperator遍历所有匹配节点,将Style字段映射为字符串(tagged/double/single/literal/folded/flow/空串/<unknown>),并作为!!str标量输出。读取样式常见的组合用法:
# 找出文档中所有双引号节点 yq '.. | select(style == "double")' sample.yml # 找出所有非默认样式节点 yq '.. | select(style != "")' sample.yml这类“先读后筛”的模式,正是对大规模/第三方 YAML 做样式审计的实用手段。
十五、底层原理小结:一条 style 表达式如何流转
- 词法:
style被识别为可赋值操作符(pkg/yqlib/lexer_participle.go); - 语法:
style="double"构造ASSIGN_STYLE操作节点(pkg/yqlib/operation.go),style单独出现则构造GET_STYLE(pkg/yqlib/operation.go); - 解析样式名:
parseStyle把字符串映射为Style常量,非法值报unknown style(pkg/yqlib/operator_style.go); - 应用样式:对 LHS 匹配到的每个
CandidateNode设置Style字段(pkg/yqlib/operator_style.go); - 输出:编码器读取节点样式,结合 tag 与 kind 决定最终 YAML 文本形态;解析 YAML 时(goccy 或 go-yaml 后端)反向识别并填充
Style(pkg/yqlib/candidate_node_goccy_yaml.go、pkg/yqlib/candidate_node_yaml.go)。
围绕这些行为的全部示例在 pkg/yqlib/operator_style_test.go 中都有对应测试用例(TestStyleOperatorScenarios),修改行为时可直接运行该测试验证。
十六、实战组合建议
- 统一团队 YAML 风格:
yq -i '... style="double"' config.yml,让所有键值引号化、格式统一,再配合-i原地写回; - 压缩输出供管道消费:
yq '.. style="flow"' data.yml | <下游工具>; - 保留多行文本语义:对特定字段(如脚本、描述)单独设置
style="literal",其余保持默认:yq '.description style="literal"' README.yml; - 安全重排引号:用
yq -P(等价'... style=""')清理第三方 YAML 中混乱的引号与 flow 形态,输出规范块式文档。
延伸阅读
- 操作符文档:pkg/yqlib/doc/operators/style.md(本文内容对应其完整章节)
- 操作符总览:pkg/yqlib/doc/operators/headers/Main.md
- 实现源码:pkg/yqlib/operator_style.go、pkg/yqlib/candidate_node.go
- 测试用例:pkg/yqlib/operator_style_test.go
- pretty print 标志:cmd/root.go、cmd/evaluate_sequence_command.go
- 输出格式化相关:pkg/yqlib/doc/usage/formatting-expressions.md、pkg/yqlib/format.go
【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考