
CLI开发工具【免费下载链接】fish-shellThe user-friendly command line shell.项目地址https://gitcode.com/GitHub_Trending/fi/fish-shell点击查看免费下载导读for是 fish shell 中最常用的循环结构用于对一组值反复执行同一段命令。本文以官方文档 doc_src/cmds/for.rst 为骨架完整讲解for的语法、空值列表行为、循环变量的作用域规则并结合仓库源码与测试用例深入剖析其底层执行流程、break/continue的配合方式以及与 3.0.0 版本之前行为差异的来龙去脉。读完本文你将能够熟练编写 fish 循环脚本并理解循环变量在函数、全局、通用作用域之间的精确归属规则。for 循环的基本语法for是一个循环结构loop construct它会将COMMANDS指定的命令执行多次。每次迭代时由VARNAME指定的局部变量会被赋予VALUES中的一个新值。官方语法如下for VARNAME in [VALUES ...]; COMMANDS ...; end其中VARNAME是循环变量名必须是合法的 fish 变量名不能是只读变量详见下文源码分析VALUES ...是迭代值列表支持通配符、命令替换、变量展开因此既可以是字面量也可以是(seq 1 10)之类的动态结果COMMANDS ...是循环体可以包含任意 fish 命令也可以嵌套其他循环、条件或函数调用end是循环块的结束关键字不可省略否则会报未配对的块错误。典型示例来自文档 Example 一节for i in foo bar baz; echo $i; end输出结果为foo bar baz语法细节同一行的for i in 1 2之后可以紧跟注释# Comment on same line注释不会影响循环解析见 tests/checks/basic.fish 中的测试用例迭代值列表可以跨行通过行尾的反斜杠续行例如for i in \换行后继续写a b c测试见 tests/checks/basic.fishfor与while一样都是块结构关键字for、end等被列入保留字reserved words不允许被重载为函数名相关定义见 src/parser_keywords.rs。空值列表循环体一次都不会执行文档明确强调如果VALUES为空COMMANDS将完全不会执行IfVALUESis empty,COMMANDSwill not be executed at all.。例如for x in echo never printed end上述循环体不会输出任何内容。这一行为在 tests/checks/for.fish 中有直接验证测试先把全局变量j设为global再执行空的for j in循环随后set -ql j echo $j输出global证明空列表下循环体未运行、变量未被改写。循环变量与作用域规则循环结束后变量仍然可见文档指出VARNAME在循环终止后仍然可见visible when the loop terminates并保存最后一次被赋予的值如果循环开始前VARNAME不存在它会被设置在局部作用域local scope中。这是 fish 3.0.0 之后的关键变化。在此之前for的循环变量只在循环块内部可见循环结束后外部无法访问。文档给出了旧版本行为示例for var in a b c if break_from_loop break end end echo $var在 3.0.0 之前的版本中echo $var输出的内容取决于循环运行前var被设置成了什么——通常是空Likely nothing。而在当前版本中循环结束后$var一定等于最后一次迭代赋予的值上例中为c。作用域的精确归属规则文档进一步说明了循环变量的作用域查找规则这是理解 fish 变量模型的关键如果for块位于函数内部那么循环体内必须存在一个同名的局部变量即循环变量以局部变量的方式与函数共享作用域如果for块不在函数内即顶层直接书写那么已存在的同名全局变量或通用变量universal会被直接使用如果同名变量在多个作用域都存在按 fish 一贯的最窄作用域优先规则更新的是最内层那个。这些规则在 tests/checks/for.fish 中有非常清晰的用例# 循环变量是封闭作用域中的局部变量 set -g i global # 隐式执行 set -l i $i for i in local end set -ql i echo $i # CHECK: local即全局变量i存在但for循环会创建局部的i并初始化为全局i的旧值循环结束后局部i仍保留local。测试文件头部注释还特别说明A for-loop-variable is a local variable in the enclosing scopefor 循环变量是封闭作用域中的一个局部变量。再来看另一个用例set -g j global for j in end set -ql j echo $j # CHECK: global空的迭代列表不执行循环体局部j在创建时被初始化为全局j的当前值因此$j输出global。嵌套循环的隔离性也有验证set -g k global begin for k in local1 echo $k # CHECK: local1 for k in local2 end echo $k # CHECK: local1内层循环结束后外层变量未被内层覆盖 end echo $k # CHECK: local1 end echo $k # CHECK: global离开 begin 块后恢复全局值这个用例同时验证了两点内层for k in local2修改的是内层循环自己创建或沿用的局部变量不会破坏外层循环的k而begin...end块结束后外层局部变量随之消失$k重新取回全局值。与 set 命令的对照文档提到Much likeset,fordoes not modify $status——即for本身不改变$status但循环体内命令的执行可以改变它the evaluation of its subordinate commands can。这与 set 命令文档 中赋值模式不修改退出状态只是透传命令替换设置的 status是同一设计理念控制结构本身不应吞掉或污染状态码让脚本作者可以依赖循环体内最后一条命令的退出状态。与 break / continue 的配合for循环通常与break提前终止循环和continue跳过本次迭代剩余部分配合使用。continue 文档 中的示例展示了典型用法——跳过所有包含smurf的临时文件for i in *.tmp if grep smurf $i continue end # 如果执行了 continue下面的 rm 会被跳过 rm $i end从底层实现看break和continue内置命令只做一件事把解析器libdata中的loop_status标记为LoopStatus::Breaks或LoopStatus::Continues见 src/builtins/shared/misc.rs。随后for的执行循环在每轮迭代结束后检查该标记从而决定是跳出还是进入下一轮详见下文实现原理。如果break/continue出现在循环之外会直接报错 Not inside of loop。源码级实现原理for语句的实际执行位于 src/parse_execution.rs 的run_for_statement函数中其执行流程与文档描述一一对应解析变量名从 AST 中取出for var_name in ...的变量名先做一次展开expand_one再校验其是否为合法变量名valid_var_name。如果变量名本身展开失败或非法报错并返回STATUS_EXPAND_ERROR或STATUS_INVALID_ARGS。校验只读变量通过EnvVar::flags_for检查变量是否为只读例如PWD这类特殊只读变量。若为只读报错 for: ...: cannot overwrite read-only variable。这一点与 tests/checks/basic.fish 中for PWD in foo bar报错的测试用例吻合。初始化循环变量在进入循环前先用set_var(..., EnvMode::LOCAL, 旧值)将循环变量按局部作用域设置旧值来自当前已存在的同名变量这正是如果 VARNAME 已存在则继承其旧值这一行为的来源。展开迭代值列表将VALUES ...整体展开为参数列表。注意通配符使用WildcardNoMatchBehavior::Allow即匹配不到任何文件时不报错、得到空列表从而保证空列表不执行循环体。驱动循环逐值把循环变量设置为当前迭代值EnvMode::default()即沿用既有作用域规则触发一次变量变更事件Event::variable_set然后push_block(Block::for_block())执行循环体中的 job list结束后pop_block清理块内变量。处理 break/continue每轮迭代检查loop_status若为LoopStatus::Breaks则跳出循环若为LoopStatus::Continues则进入下一轮。循环开始时会把loop_status重置为Normals。此外for作为保留字其解析与while、begin、function等块结构共用同一套块语句分发逻辑src/parse_execution.rs这也是 fish 各种块结构在解析和报错行为上高度一致的原因。变量变更事件循环每次迭代都会触发Event::variable_set事件。这意味着你可以用function --on-variable foo之类的函数监听循环变量的每一次更新。这一行为同样有测试覆盖tests/checks/for.fish对for foo in 1 2 3循环监听foo变量的函数被触发了三次CHECK: foo set出现三行。实战示例组合运用以上特性可以写出既简洁又符合 fish 风格默认变量即列表的循环脚本。遍历文件并对每个文件执行操作for f in *.log echo processing $f end配合命令替换动态生成迭代列表for i in (seq 1 5) echo item $i end提前跳出循环for i in (seq 1 10) if test $i -eq 3 break end echo $i end # 输出 1 2循环结束后继续使用最后一个值for server in db web cache echo starting $server end echo last was $server # 输出 last was cache嵌套循环打印二维组合for i in 1 2 for j in a b echo $i$j end end # 输出 1a 1b 2a 2b最后一个例子直接来自 tests/checks/basic.fish 的测试用例验证了多行注释、循环体内注释以及嵌套循环均可正常工作。总结与版本注意事项for VARNAME in VALUES...; COMMANDS; end是 fish 的循环核心语法VALUES为空则循环体完全不执行3.0.0 起循环变量在循环结束后仍然可见并保留最后赋给它的值3.0.0 之前循环变量仅限循环块内部外部echo $var通常为空——升级旧脚本时请留意这一行为差异循环变量默认落在局部作用域函数内与函数局部作用域共享顶层则沿用已存在的全局/通用变量找不到时按 fish 规则新建局部变量for本身不修改$status循环体内命令的退出状态可以自由透传底层实现可查阅 src/parse_execution.rs行为测试可查阅 tests/checks/for.fish 与 tests/checks/basic.fish相关命令文档见 for、while、break、continue、set。赞分享CLI开发工具【免费下载链接】fish-shellThe user-friendly command line shell.项目地址https://gitcode.com/GitHub_Trending/fi/fish-shell点击查看免费下载相关推荐告别环境变量混乱Fish Shell作用域与导出机制全解析告别环境变量混乱Fish Shell作用域与导出机制全解析 Fish Shell 作为一款用户友好的命令行 shell提供了清晰的环境变量管理机制帮助用户CLI开发工具Fish Shell 3.7.1 中局部变量作用域问题的技术分析Fish Shell 3.7.1 中局部变量作用域问题的技术分析 在 Fish Shell 3.7.1 版本中发现了一个关于局部变量作用域的有趣问题这个问题涉CLI开发工具Roc 语言嵌套 for 循环实战基于 REPL 快照测试解析迭代、变量重赋值与作用域Roc 语言嵌套 for 循环实战基于 REPL 快照测试解析迭代、变量重赋值与作用域 本指南以 Roc 仓库中 REPL 快照测试 for_loop_nes上一篇Streama视频弹幕功能实现WebSocket与前端渲染下一篇3步构建LLM评估可视化系统从黑箱测试到透明分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考