ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

yq Pipe 管道操作符:把一个表达式接进下一个表达式

yq Pipe 管道操作符:把一个表达式接进下一个表达式 yq Pipe 管道操作符把一个表达式接进下一个表达式【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yqyq 是一款可移植的 YAML、JSON、XML、CSV、TOML、HCL 与 properties 文件处理器它的查询语言中最核心的“粘合剂”就是管道Pipe操作符|。本篇基于仓库文档 pipe.md 展开先完整覆盖文档中的简单管道与连续更新两个用法再结合 yq 的词法解析、操作符注册与求值器源码讲清楚|的优先级、求值时机与上下文传递机制帮助你写出可预测、可组合的 yq 表达式。什么是 Pipe把表达式的结果喂给下一个表达式Pipe 的行为与 Bash 中的|类似左边表达式的匹配结果成为右边表达式的输入上下文。在 yq 中这个“结果”是一组候选节点candidate nodes——既可能是值本身也可能是带有路径信息的节点这样赋值操作才能写回原文档。官方文档对 Pipe 的一句话定义是“Pipe the results of an expression into another. Like the bash operator.”把一个表达式的结果传给另一个表达式就像 Bash 操作符一样。简单管道逐级深入取值文档给出的第一个例子给定一个sample.yml文件a: b: cat执行yq .a | .b sample.yml输出cat执行过程可以拆解为两步.a在文档上求值得到节点b: cat这个映射子树路径a管道把该子树作为新的输入上下文.b在子树上求值得到标量cat。也就是说.a | .b等价于写.a.b但拆成两段管道后你可以在中间插入任意变换操作这正是管道表达力的来源。例如在包含数组的数据上yq .a[] | select(.b cat) sample.yml # 先展开数组再过滤管道两侧的表达式各自独立求值右侧表达式的起点是左侧的终点这使 yq 表达式天然适合链式组合select、map、sort等单目/遍历操作符都常与|搭配使用相关文档见 select.md、map.md。连续更新管道串起多个赋值文档的第二个例子展示了管道在“写”方向的价值。给定sample.ymla: cow b: sheep c: same执行yq .a cat | .b dog sample.yml输出a: cat b: dog c: same三个要点从左到右依次执行.a cat先完成文档状态更新后.b dog在此基础上执行最后c: same未被触及而原样保留每条更新都作用于同一份文档与“读取结果再传递”不同赋值类操作直接修改文档树管道只是规定了操作的先后顺序更新表达式可以很长把一次复杂的文档变换拆成多个以|分隔的小步骤是 yq 表达式可读性的关键实践。仓库中的测试用例 operator_pipe_test.go 精确复现了文档这两个例子{ description: Simple Pipe, document: {a: {b: cat}}, expression: .a | .b, expected: []string{ D0, P[a b], (!!str)::cat\n, }, }, { description: Multiple updates, document: {a: cow, b: sheep, c: same}, expression: .a cat | .b dog, expected: []string{ D0, P[], (!!map)::{a: cat, b: dog, c: same}\n, }, },测试中的P[a b]表示最终节点路径为a.b说明管道确实逐级推进了路径P[]表示第二个例子的结果是文档根节点本身更新后输出整份文档。变量与管道as $x |的专门入口yq 的变量赋值expr as $x | ...在求值器层面是走管道分支的。pipe.md 未展开这一点但源码 operator_pipe.go 中有明确的专门处理func pipeOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { if expressionNode.LHS.Operation.OperationType assignVariableOpType { return variableLoop(d, context, expressionNode) } lhs, err : d.GetMatchingNodes(context, expressionNode.LHS) ... rhsContext : context.ChildContext(lhs.MatchingNodes) rhs, err : d.GetMatchingNodes(rhsContext, expressionNode.RHS) ... return context.ChildContext(rhs.MatchingNodes), nil }当管道左侧是变量赋值as时会转交给 variableLoop 处理该文件中的注释直接说明设计意图——“variables are like loops in jq”变量像 jq 中的循环一样逐值展开执行右侧。而普通管道则严格按两阶段执行GetMatchingNodes(context, LHS)在当前上下文上求值左表达式context.ChildContext(lhs.MatchingNodes)用左侧匹配结果构造子上下文在子上下文上求值右表达式其结果成为管道整体输出。变量操作的约束同样写在代码里useWithPipe会在未配合管道使用时报错must use with a pipe, e.g. exp as $x | ...且 RHS 必须是变量名见 variableLoopSingleChild。优先级管道在表达式中处于哪一层|的词法识别在 lexer_participle.go 中注册{Pipe, \|, opToken(pipeOpType), 0}其操作符定义在 operation.govar pipeOpType operationType{Type: PIPE, NumArgs: 2, Precedence: 30, Handler: pipeOperator}对照 operation.go 中全部操作符的优先级数字越大结合越紧管道处于一个关键的分界位置从低到高大致为优先级操作符说明10union、块a // b并集、括号块15CREATE_MAP对象字面量{...}的构建20OR/AND布尔运算or/and30PIPE普通管道\|35REDUCE归约40ASSIGN/EQUALS等赋值、比较42MULTIPLY、ADD、ALTERNATIVE*、、备选//相关运算45SHORT_PIPE集合/对象字面量内部的短管道如[... | ...]50LENGTH、SORT、COLLECT等无参/单参数后缀操作由此得到三条实用的求值规则赋值高于管道.a cat | .b dog被解析为(赋值) | (赋值)而不是.a (cat | .b...)。这就是“连续更新”能成立的原因布尔运算低于管道x and y | z中and一侧的表达式会先被管道切开需要用括号显式控制结合关系算术/备选优先于管道a b | upper会先完成拼接再进管道。此外源码中还定义了 shortPipeOpType优先级 45它与pipeOpType共用同一个pipeOperator处理器服务于[... | ...]这类集合内部语法普通表达式中书写|时对应的是上表的PIPE。上下文的传递与“只读”保护理解管道的第二个关键点在于上下文如何跨|传递。每个求值步都携带一个Context见 context.go核心字段包括type Context struct { MatchingNodes *list.List // 当前匹配到的候选节点 Variables map[string]*list.List // 管道间共享的变量 DontAutoCreate bool // 只读标志禁止自动创建路径 datetimeLayout string }ChildContext在克隆上下文时复制变量表但保留候选节点引用源码注释解释了原因不复制节点才能让ref引用操作符正常工作——即左侧表达式如果返回的是文档中真实存在的节点而非值拷贝右侧的修改会写回原树。这正是.a | .b x能真正改到a.b的机制。测试文件中的第三个用例专门验证了“管道不把只读状态泄漏给右侧”{ description: Dont pass readonly context, expression: (3 4) | ({} | .b dog), expected: []string{ D0, P[], (!!map)::b: dog\n, }, },左侧(3 4)产生的是纯数值结果对映射求值属于只读语义但管道右侧{}开启的新对象字面量是全新的可写节点因此.b dog正常执行并输出b: dog。换句话说只读保护作用于“读取既有节点”的路径而不会阻塞在管道右侧构造的新节点上的写入。小结回到 pipe.md 的核心内容读取场景.a | .b逐级深入每段表达式都以上一段的输出为起点更新场景.a cat | .b dog从左到右依次修改同一份文档未涉及的键保持不变实现层面PIPE操作符优先级 30处理器 pipeOperator两阶段求值——先算左侧、用ChildContext传递匹配节点、再算右侧变量as走同一入口但由 variableLoop 逐值展开。掌握这三层你就能在任何 yq 表达式中正确预测|的结合与执行顺序把复杂的查询与批处理改写为清晰、可维护的管道链。【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表