news 2026/9/14 4:51:35

yq Style 操作符完全指南:读取与设置 YAML 节点样式(引号、标签、Flow 与多行块)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
yq Style 操作符完全指南:读取与设置 YAML 节点样式(引号、标签、Flow 与多行块)

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)会逐个拼接出如TaggedStyleDoubleQuotedStyle这样的可读名称。

二、支持的样式值一览

写入样式时,字符串会被 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(类型)。bce的取值仍是字符串形态的数字与布尔字面量,但 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"

对比上一节:.....多匹配一层——递归下降时同时命中键节点与值节点,因此键abcegsomething也都带上了双引号。这在生成“所有键值都必须引号化”的 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: cool

yq 为此提供了专用短标志。在 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 表达式如何流转

  1. 词法style被识别为可赋值操作符(pkg/yqlib/lexer_participle.go);
  2. 语法style="double"构造ASSIGN_STYLE操作节点(pkg/yqlib/operation.go),style单独出现则构造GET_STYLE(pkg/yqlib/operation.go);
  3. 解析样式名parseStyle把字符串映射为Style常量,非法值报unknown style(pkg/yqlib/operator_style.go);
  4. 应用样式:对 LHS 匹配到的每个CandidateNode设置Style字段(pkg/yqlib/operator_style.go);
  5. 输出:编码器读取节点样式,结合 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 4:50:23

魔兽世界76级高效刷本升级攻略与副本推荐

1. 魔兽世界76级高效刷经验副本选择指南作为一款运营多年的经典MMORPG&#xff0c;《魔兽世界》的升级过程一直是玩家关注的重点。对于76级的玩家来说&#xff0c;找到合适的刷经验地点可以大幅提升升级效率。本文将详细介绍几个适合76级玩家无限刷怪的副本&#xff0c;以及相关…

作者头像 李华
网站建设 2026/9/14 4:47:23

Python单元测试实战:unittest框架与最佳实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 4:47:22

社区智慧康养底座怎么搭?从数据闭环到运营实战的深度解析

去年底我回访一个已经上线运营半年的社区智慧康养项目&#xff0c;服务中心负责人见到我第一句话是&#xff1a;“你们那个智能床垫真好使&#xff0c;李阿姨前天夜里心率异常&#xff0c;系统直接报警&#xff0c;我和家属十分钟之内赶到了。”第二句话紧接着就是&#xff1a;…

作者头像 李华
网站建设 2026/9/14 4:46:55

提示工程实战:四层结构化设计与工业级落地方法

1. 提示工程&#xff1a;不是写作文&#xff0c;是调校AI的精密扳手“提示工程”这个词最近在技术圈、内容创作圈甚至产品经理例会上频繁冒头&#xff0c;但它绝不是给大模型发个“请写一篇春天的散文”就完事的简单操作。我带过6个AI应用落地项目&#xff0c;从电商文案生成到…

作者头像 李华
网站建设 2026/9/14 4:46:37

SpringBoot集成阿里云SLS日志服务:Java Producer自动装配实践

简介&#xff1a;面向Java后端开发者&#xff0c;这一SpringBoot封装项目基于阿里云日志服务Java生产者SDK&#xff0c;提供开箱即用的日志采集与上报能力&#xff0c;适用于微服务架构下的日志集中管理、监控排障与业务分析等场景。压缩包内共19个文件&#xff0c;包括13个Jav…

作者头像 李华
网站建设 2026/9/14 4:46:37

干了多年嵌入式,最后悔的几件事:写给新手的避坑指南

干了这么多年嵌入式&#xff0c;我最后悔的几件事说实话&#xff0c;干嵌入式这行越久&#xff0c;越觉得“后悔”是个挺有分量的词。我从裸机单片机做起&#xff0c;一路折腾过STM32、嵌入式Linux、各种协议栈&#xff0c;到现在回头看&#xff0c;真正让我睡不着觉的不是哪段…

作者头像 李华