ShellCheck 开发指南:构建、架构解析与新检查项的编写实践
ShellCheck 开发指南构建、架构解析与新检查项的编写实践【免费下载链接】shellcheckShellCheck, a static analysis tool for shell scripts项目地址: https://gitcode.com/gh_mirrors/sh/shellcheckShellCheck 是一个用 Haskell 编写的 shell 脚本静态分析工具能够在脚本执行前发现常见错误、陷阱与风格问题。本指南面向希望参与 ShellCheck 开发的贡献者完整覆盖仓库内的构建与测试命令、三阶段流水线架构、关键源码文件映射以及从零新增一条检查项的标准流程帮助读者快速上手开发环境并理解底层实现原理。构建与测试日常开发的完整命令集仓库根目录的.claude/CLAUDE.md给出了从编译、单测到调试的整套命令。这些命令都基于 Cabal/GHC 工具链前提是本地已安装 GHC 与 cabal-install。标准编译与测试cabal build # 编译 cabal test # 运行单元测试权威来源 source of truth cabal run shellcheck -- file.sh # 对文件执行检查 cabal run shellcheck - cmd # 对内联输入执行检查其中cabal test被明确标注为测试的 source of truth权威来源因为 test/shellcheck.hs 会聚合ShellCheck.Analytics、ShellCheck.Parser、ShellCheck.Checks.Commands、ShellCheck.CFGAnalysis等全部模块的runTests任何一个模块的测试失败都会导致整体退出码非零。该文件顶部mapM sequenceA tests逐模块收集测试结果最终打印失败的模块名并以exitFailure结束。免编译的解释执行模式每次改动都重新编译会拖慢迭代节奏仓库为此提供了两个解释执行脚本./quickrun - cmd # 解释模式运行快速、无需重新编译 ./quicktest # 解释模式跑测试快速、无需重新编译从 quickrun 的源码可以看到它先通过find在dist*构建目录中定位Paths_ShellCheck.hs第一次使用前必须至少执行过一次cabal build否则会报错退出随后用runghc -isrc直接解释执行 shellcheck.hs。quicktest 的原理类似但它借助ghci加载 test/shellcheck.hs通过判断输出中是否包含ExitSuccess来判定测试是否全部通过。申请新的警告编号ShellCheck 的每条检查项都有独立的SC1xxx语法/解析、SC2xxx分析或SC3xxx数据流/CFG编号./nextnumber # 打印下一个可用的 SC1xxx/SC2xxx/SC3xxx 编号nextnumber 脚本要求 Bash 4依赖globstar其实现是遍历仓库内所有.hs文件用正则提取形如1xxx、2xxx、3xxx的数字并取最大值加一分别输出三段编号的下一个可用值。在新增检查项之前运行它可以避免与现有警告编号冲突。交互式 REPL 开发对于需要反复试错的场景文档推荐进入 GHCi 交互环境cabal repl # 进入交互式 REPL # 之后在 GHCi 中 # :load ShellCheck.Debug # 加载调试辅助模块 # :r # 编辑源码后重载 # shellcheckString your shell code # 直接对字符串执行完整检查shellcheckString定义在 Debug.hs返回一个完整的CheckResult非常适合在不写测试的情况下快速验证新检查项的行为。不进入交互会话直接看 AST在 shellcheck-dev.hs 中提供了一个专为开发官方注释明确提到其潜在受益者是 AI/自动化工具设计的子命令入口cabal run -fdev-mode shellcheck-dev -- ast myshellcommandshellcheck-dev通过-fdev-modeCabal flag 启用目前只注册了ast一个子命令内部调用Debug.stringToAst见 Debug.hs将一行 shell 命令解析并打印为 Token 树是理解解析结果的最直接手段。注意cabal run -fdev-mode意味着需要以 dev-mode 特性重新编译该目标。架构三阶段流水线ShellCheck 处理一份 shell 脚本时严格经过三个阶段.claude/CLAUDE.md的 Architecture 一节:Parsing解析——核心实现在 Parser.hs。基于 Parsec 组合子解析器把源码转换为 AST同时产出 SC1xxx 编号的警告。解析器注释parser notes是非致命的会被缓存起来一旦整个解析失败即被丢弃而解析器问题parser problems是致命的永远会被保留并输出。AST AnalysisAST 分析——核心实现在 Analytics.hs 以及 Checks/ 目录下遍历 AST 并产出 SC2xxx/SC3xxx 编号的警告。Output输出——核心实现在 Formatter/ 目录把诊断结果格式化为 TTY、JSON、GCC 风格、diff 等不同输出形式。三个阶段在 shellcheck.hs 的main中串联process解析命令行参数与SHELLCHECK_OPTS环境变量用空格切分写在命令行参数之前生效为每个输入文件构造CheckSpec调用checkScript完成解析与分析最后交给 formatter 渲染结果。各阶段职责的源码佐证解析阶段Parser.hs产出的是TokenAST节点类型定义在 AST.hs。解析器对语法错误和非致命注释的差异化处理决定了后续分析器能拿到什么样的输入。分析阶段Analytics.hs 定义了treeChecks在 AST 根节点上运行一次的整体性检查如checkUnusedAssignments、checkShebang、checkUnassignedReferences与nodeChecks对每个节点运行如checkPipePitfalls、checkForInLs。nodeChecksToTreeCheck会把所有 node check 折叠成一次遍历保证整棵树的节点检查只走一遍。此外还有独立的 CFG 体系CFG.hs 与 CFGAnalysis.hs支撑 Checks/ControlFlow.hs 中的数据流分析。输出阶段shellcheck.hs中的formats映射shellcheck.hs注册了七种格式器checkstyle、diff、gcc、json、json1、tty、quiet对应Formatter/目录下的同名模块。关键源码文件速查表.claude/CLAUDE.md给出了与各阶段对应的关键文件映射完整罗列如下文件用途src/ShellCheck/AST.hsToken 类型定义AST 节点类型src/ShellCheck/ASTLib.hs操作 AST 节点的辅助函数如getLiteralStringsrc/ShellCheck/Analytics.hs主分析器treeChecks与nodeChecks列表src/ShellCheck/AnalyzerLib.hs检查项作者的共享工具warn、err、style等src/ShellCheck/Checks/Commands.hs按命令名分发的逐命令检查src/ShellCheck/Checks/ShellSupport.hs按 shell 方言分发的检查src/ShellCheck/Checks/ControlFlow.hs控制流 / CFG 检查src/ShellCheck/CFG.hs、CFGAnalysis.hs控制流图构建与分析src/ShellCheck/Parser.hs基于 Parsec 的 shell 解析器src/ShellCheck/Interface.hs公共 API 类型CheckResult、PositionedComment等src/ShellCheck/Debug.hs开发辅助stringToAst、shellcheckString等其中 Interface.hs 定义的数据结构是理解各阶段数据流的钥匙CheckSpec输入规格脚本内容、shell 方言、排除/包含的警告等、CheckResult输出结果、Comment与PositionedComment带位置的诊断注释被各 formatter 消费。新增一条检查项的标准流程Adding a check一节是给贡献者的核心操作手册下面结合源码展开说明。检查的两种形态绝大多数检查都定义在 Analytics.hs 中且只有两种形态Node checks节点检查——对 AST 的每个节点运行追加到nodeChecks列表。例如checkPipePitfalls、checkUnquotedDollarAt这类逐点扫描式的检查。Tree checks树检查——只在根节点运行一次追加到treeChecks列表。例如checkUnusedAssignments、checkUnassignedReferences这类需要跨整个脚本收集信息的检查。当检查器需要多次遍历整棵树时也可以写成树检查。从 Analytics.hs 的checker可以看到mkChecker会把treeChecks与所有启用/可选的检查合并在perScript中一次性应用到 AST 根节点。检查项的函数签名检查是纯函数签名为Parameters - Token - Writer [TokenComment] ()即输入解析参数与 AST 节点通过 Writer monad 追加诊断注释。要输出诊断使用 AnalyzerLib.hs 提供的四个辅助函数warn id code str -- WarningC 级别 err id code str -- ErrorC 级别 info id code str -- InfoC 级别 style id code str -- StyleC 级别它们底层都调用makeComment把给定的IdToken 节点 ID、Code如SC2155和消息文本包装成TokenComment。选用哪个级别决定了默认-S/--severity阈值下该警告是否可见默认最小级别为style见 shellcheck.hs。配套单元测试prop_ 约定每条检查项上方都必须配prop_开头的单元测试正反两个方向各覆盖一次prop_checkFoo1 verify checkFoo bad shell code prop_checkFoo2 verifyNot checkFoo good shell codecabal test会自动发现并运行所有prop_函数这也是 Analytics.hs 中Test.QuickCheck.All.forAllProperties的作用——把每个prop_当作一个 QuickCheck 属性批量执行。提交前必须保证cabal test全绿。检查的归类放置与具体命令强相关的检查如cat、grep、find的使用模式放在 Checks/Commands.hs这类检查按命令名分派与 shell 方言强相关的检查如sh与bash语法差异放在 Checks/ShellSupport.hs按方言分派其余通用检查直接进 Analytics.hs 的nodeChecks/treeChecks。AST 编码约定只用糖衣模式别名ShellCheck 的 AST 存在两套表示方式文档明确要求检查项代码中一律使用糖衣sugared模式别名T_Literal id str -- 字面量 T_IoFile id op filename -- 文件重定向而绝不要直接写脱糖后的内部类例如OuterToken (Id id) (Inner_T_Literal str)后者是 GHC 的内部表示一旦出现在检查项代码中既难以阅读也极易出错。这套别名的定义位置在 AST.hs 中配合 ASTLib.hs 的辅助函数如getLiteralString可以写出简洁且稳健的模式匹配。开发规范速查.claude/CLAUDE.md的 Guidelines 总结了提交前必须遵守的检查清单新增和修改的检查项都要配单元测试且正反用例都要覆盖改动保持聚焦避免为传递新数据而做大规模重构要考虑命令的等价形式例如echo foo bar与echo bar foo语义相同检查不能漏掉其中一种始终确认cabal test干净通过通过cabal run shellcheck - bad code或./quickrun做端到端验证确认警告确实按预期触发。端到端验证之所以重要是因为单元测试只验证检查函数本身而真实场景还涉及 shell 方言识别、.shellcheckrc配置、-e/-i过滤与 formatter 渲染等整条链路。例如 shellcheck.hs 中注册了-s/--shell方言、-S/--severity最小级别、-i/--include、-e/--exclude、-o/--enable、-f/--format、-x/--external-sources、--norc、--rcfile、-P/--source-path、--extended-analysis、--list-optional、--files-from等选项其中-e/-i/-o支持逗号分隔并可重复出现、parseNum还兼容SC前缀shellcheck.hs。这些都会影响检查最终是否被触发值得在提交前用真实脚本跑一遍。另外主程序用不同的退出码区分失败原因shellcheck.hs0无问题、1存在警告/错误、2运行时异常、3语法错误如非法参数、4不支持的功能如未知格式名。在 CI 或脚本中集成时可以据此精确判断失败类别。总结从.claude/CLAUDE.md出发结合仓库源码可以看到 ShellCheck 是一个结构清晰、易于扩展的静态分析器cabal工具链负责编译与测试quickrun/quicktest提供免编译的快速迭代通道nextnumber管理警告编号资源核心代码严格遵循「解析 → AST 分析 → 格式化输出」的三阶段流水线新增检查项只需在Analytics.hs或Checks/下按 node/tree 两种形态注册一个纯函数并配齐prop_测试再遵循糖衣 AST 别名等编码约定即可。掌握这套流程后无论是修复误报、增强现有检查还是提交全新的 SC 编号警告都可以在既有架构内高效完成。【免费下载链接】shellcheckShellCheck, a static analysis tool for shell scripts项目地址: https://gitcode.com/gh_mirrors/sh/shellcheck创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

依赖审计实战:以 agent-governance-toolkit 的 @typescript-eslint/eslint-plugin 补丁升级为例,解析依赖变更治理全流程

依赖审计实战:以 agent-governance-toolkit 的 @typescript-eslint/eslint-plugin 补丁升级为例,解析依赖变更治理全流程

依赖审计实战:以 agent-governance-toolkit 的 typescript-eslint/eslint-plugin 补丁升级为例,解析依赖变更治理全流程 【免费下载链接】agent-governance-toolkit AI Agent Governance Toolkit — Policy enforcement, zero-trust identity, execution…

2026/9/19 1:50:33 阅读更多 →
电机故障诊断深度学习实战:从振动信号到边缘部署

电机故障诊断深度学习实战:从振动信号到边缘部署

简介:这份PDF文献面向电气工程、自动化及机械故障诊断方向的研究生与工程技术人员,聚焦深度学习在电机故障诊断中的落地方法,帮助读者理解如何用堆栈稀疏自编码器替代传统浅层神经网络,解决易陷入局部极小值、特征依赖人工经验等问…

2026/9/19 1:50:33 阅读更多 →
ChatDev 2.0 Dynamic 执行模式深度指南:边级 Map 扇出与 Tree 归约的并行编排实战

ChatDev 2.0 Dynamic 执行模式深度指南:边级 Map 扇出与 Tree 归约的并行编排实战

ChatDev 2.0 Dynamic 执行模式深度指南:边级 Map 扇出与 Tree 归约的并行编排实战 【免费下载链接】ChatDev ChatDev 2.0: Dev All through LLM-powered Multi-Agent Collaboration 项目地址: https://gitcode.com/Dennis_Huang/ChatDev ChatDev 2.0 的 Dyna…

2026/9/19 1:49:33 阅读更多 →

最新新闻

ISO 17021-10审核员能力评估:从危险源辨识到持续适任的完整框架

ISO 17021-10审核员能力评估:从危险源辨识到持续适任的完整框架

简介:ISO IEC TS 17021-10:2018《职业健康与安全管理系统的审核和认证能力要求》完整英文版,面向从事OH&S MS审核、认证及相关合规工作的专业人士。规范系统规定了审核员与认证机构的知识、技能、经验、道德行为及持续发展要求,涵盖范围、…

2026/9/19 2:32:58 阅读更多 →
Android RS-485通信实战:解决阻塞读取与方向控制两大深坑

Android RS-485通信实战:解决阻塞读取与方向控制两大深坑

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

2026/9/19 2:32:58 阅读更多 →
Matlab实现莱斯信道下QPSK仿真与星座图畸变分析

Matlab实现莱斯信道下QPSK仿真与星座图畸变分析

简介:本资源是一份面向通信工程专业学生、无线通信方向研究者及Matlab仿真初学者的实践型教学文档,聚焦莱斯信道下QPSK信号传输特性的建模与仿真分析。文档系统讲解了移动无线信道分类、小尺度衰落机理、瑞利与莱斯分布的物理意义及K因子对误比特率的影响…

2026/9/19 2:32:58 阅读更多 →
Java安卓外卖订餐系统课程设计实战:从选型到订单状态机

Java安卓外卖订餐系统课程设计实战:从选型到订单状态机

简介:面向Java/Android学习者的外卖订餐系统课程设计报告,完整记录了从需求分析到项目落地的全过程。文档以软件工程规范为纲,先阐述课程设计目的与任务,再展开需求分析,包含数据流图、用例图、时序图、活动图等建模内…

2026/9/19 2:32:58 阅读更多 →
国产MQTT协议栈选型指南:从License合规到边缘性能实战

国产MQTT协议栈选型指南:从License合规到边缘性能实战

1. 项目概述:为什么国产 MQTT 协议栈不是“换个名字”,而是架构级的重新选择最近三个月,我连续接手了四个工业物联网项目,客户提的需求高度一致:“能不能不用 Mosquitto 或 EMQX?最好用国产的。”起初我以为…

2026/9/19 2:32:58 阅读更多 →
GTM与GA4事件追踪实战:从埋点原理到排错技巧全解析

GTM与GA4事件追踪实战:从埋点原理到排错技巧全解析

做网站分析这一行,埋点永远是个绕不开的活儿。刚入行那会儿,我最烦的就是为了一两个按钮统计去麻烦开发改代码,提个需求排期三五天,改完上线再等数据积累,黄花菜都凉了。后来开始用GTM统一管理GA的追踪代码&#xff0c…

2026/9/19 2:31:58 阅读更多 →

日新闻

BP神经网络时序预测:滑窗长度与多窗口平均策略

BP神经网络时序预测:滑窗长度与多窗口平均策略

简介:面向机器学习、深度学习与数据建模学习者的一份完整研究文献,聚焦BP神经网络在农业产量预测中的应用。文档以1980—2018年全国棉花产量为样本,系统讲解数据归一化处理、激活函数原理、多层神经网络结构搭建及训练流程,展示敏…

2026/9/19 0:00:30 阅读更多 →
Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

Transformer训练实时监控实战:基于MindSpore的损失曲线可视化方案

上个月调一个Deformable DETR模型,在单卡上要跑将近两天。第二天早上我下意识打开终端翻日志,发现loss从凌晨两点就开始往上爬,一路从0.8涨到1.35,整整六个小时没人发现。那六个小时的训练不仅白跑,还霸占着卡——等于…

2026/9/19 0:00:30 阅读更多 →
OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南

OpenCloud 中的 Go 类型安全转换库 spf13/cast:从零值回退到泛型 API 的完整实战指南 【免费下载链接】opencloud 🌤️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign. 项目地址: htt…

2026/9/19 0:00:30 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/16 19:03:19 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/17 7:57:36 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/17 10:19:14 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →