ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

yq 的 shuffle 操作符:用非加密安全随机打乱数组顺序

yq 的 shuffle 操作符:用非加密安全随机打乱数组顺序 yq 的 shuffle 操作符用非加密安全随机打乱数组顺序【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yqshuffle 是 yqpkg/yqlib/doc/operators/shuffle.md 所定义的文档主题中用于随机打乱数组元素顺序的操作符适用于 YAML、JSON、XML、CSV、TOML 等一切以数组形式存在的节点。读完本文你将掌握yq shuffle与yq .cool | shuffle两种用法理解其底层基于math/rand的实现原理与非加密安全这一关键约束并能结合实际场景与其他操作符组合使用。shuffle 是什么一条无参数、作用于数组的管道操作符shuffle是一条无参数操作符作用是把当前上下文中的数组元素顺序随机打乱。它与其他数组类操作符如reverse、sort在表达式中的位置相同属于管道语义例如yq shuffle sample.yml会直接对输入文档的根节点必须是数组进行洗牌。从源码结构看shuffle 在操作符注册表中被定义为pkg/yqlib/operation.go 中声明了操作类型var shuffleOpType operationType{Type: SHUFFLE, NumArgs: 0, Precedence: 52, Handler: shuffleOperator, CheckForPostTraverse: true}其中NumArgs: 0表示不接受参数Precedence: 52是它的优先级CheckForPostTraverse: true表示该操作会消费当前节点pkg/yqlib/lexer_participle.go 中通过simpleOp(shuffle, shuffleOpType)将关键字shuffle注册进词法分析器因此它在表达式中以小写关键字的形式出现。基础用法直接打乱数组yq shuffle假设存在一个sample.yml文件内容为- 1 - 2 - 3 - 4 - 5执行yq shuffle sample.yml输出顺序随机以下仅为一次可能的运行结果- 5 - 2 - 4 - 1 - 3由于每次执行使用的时间种子不同同样的输入会得到不同的输出顺序这正是洗牌的预期行为。该示例与 pkg/yqlib/operator_shuffle_test.go 中Shuffle array场景的document: [1, 2, 3, 4, 5]、expression: shuffle一一对应。原地修改结合|更新映射中的数组yq .cool | shuffle如果数组不是根节点而是某个键下的值则需要用更新操作符|把 shuffle 的结果写回原位置。假设sample.yml内容为cool: - 1 - 2 - 3 - 4 - 5执行yq .cool | shuffle sample.yml输出一次可能的运行结果cool: - 5 - 2 - 4 - 1 - 3这里.cool先定位到cool键对应的数组| shuffle将该数组打乱后赋值回去同时保留cool这一外层映射结构。这与 pkg/yqlib/operator_shuffle_test.go 中Shuffle array in place场景document: cool: [1, 2, 3, 4, 5]、expression: .cool | shuffle完全一致也是实际项目中最常见的用法——例如随机挑选一批服务、打乱负载均衡的后端列表。源码实现math/rand Fisher–Yates 洗牌shuffle 的核心实现在 pkg/yqlib/operator_shuffle.go 中整体流程如下创建随机源myRand : rand.New(rand.NewSource(Now().UnixNano()))以当前系统时间的纳秒数为种子初始化math/rand遍历匹配节点对context.MatchingNodes中的每个候选节点逐一处理类型校验若节点Kind ! SequenceNode即不是数组/序列直接返回错误node at path [%v] is not an array (its a %v)其中%v分别是节点路径与节点标签拷贝再打乱先candidate.Copy()复制节点避免污染原树然后调用myRand.Shuffle(len(a), ...)对元素做 Fisher–Yates 原地洗牌同步维护 Key交换元素的同时交换a[i].Key.Value与a[j].Key.Value保证元素与其对应的键索引保持一致这关系到keys、path等依赖 Key 的操作符在后续管道中的正确性返回结果将所有处理后的节点放入新的results列表通过context.ChildContext(results)交给管道中的下一个操作符。为什么不是加密安全随机CWE-338 与 math/rand 的取舍文档明确强调This command doesnotuse a cryptographically secure random number generator。源码中同样以注释形式记录了这一设计决策// ignore CWE-338 gosec issue of not using crypto/rand // this is just to shuffle an array rather generating a // secret or something that needs proper rand. myRand : rand.New(rand.NewSource(Now().UnixNano())) // #nosec含义是shuffle的定位是打乱数组顺序这类不需要密码学强度的场景而不是生成密钥、Token 或口令等敏感随机数。math/rand由时间种子驱动、可预测性较强若用于安全敏感用途存在被枚举种子预测输出的风险对应 CWE-338因此源码中用#nosec显式声明忽略该告警。实际使用中应当遵循这一边界对数组做展示、抽样、负载分配等非安全用途用shuffle没有问题一旦涉及安全随机需求请使用openssl rand等专用工具不要依赖shuffle。与其他操作符组合管道与索引访问从 pkg/yqlib/operator_shuffle_test.go 与 pkg/yqlib/operator_delete_test.go 的测试场景可以看到 shuffle 可以自由参与管道组合yq shuffle[] sample.yml先打乱整个数组再通过[]展开为每个元素一条记录输出yq shuffle | del(.[2])打乱后删除新顺序下索引为 2 的元素常用于随机剔除一个成员之类的场景因为 shuffle 的Precedence: 52与sort、reverse、first等一致它可以在表达式任意需要数组结果的位置出现。文档即测试shuffle.md 由测试用例自动生成值得说明的是pkg/yqlib/doc/operators/shuffle.md 并非手写维护而是由 pkg/yqlib/operators_test.go 中的documentOperatorScenarios机制从shuffleOperatorScenarios测试用例自动渲染生成的每个场景的description成为##小节标题document成为输入示例运行结果写入 will output。这意味着文档中展示的每个例子都可以在go test -run TestShuffleByOperatorScenariospkg/yqlib/operator_shuffle_test.go下复现验证文档内容与真实行为严格同步。小结与注意事项基本用法yq shuffle sample.yml打乱根数组yq .cool | shuffle sample.yml原地打乱映射中的数组只接受数组输入对非数组节点会报错 node at path [...] is not an array随机源为math/rand时间种子非加密安全禁止用于安全敏感随机场景shuffle 会拷贝节点再打乱不会改动输入文档的原始内存树结合|才真正写回每次执行结果随机无法复现上一次的顺序若需可复现请自行设置随机种子当前实现未暴露该选项。【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表