当前位置: 首页 > news >正文

Shell脚本精读 · S12-02 | 语法检查与 ShellCheck:静态发现问题

模块:S12 调试、测试与排错
篇号:S12-02 / 42
预计阅读:45 分钟
主线:Bash


文章目录

    • 本篇目标
    • 30 秒速览
    • 正文
      • 1. 静态检查 vs 动态调试
      • 2. `bash -n`:仅语法
      • 3. 安装与基本用法
      • 4. 输出长什么样
      • 5. 高频 SC 与专栏篇目对照
      • 6. 示例:改前 / 改后
        • 6.1 SC2086
        • 6.2 SC2164
        • 6.3 SC2181
        • 6.4 SC2046
      • 7. `source` 与 SC1090
      • 8. 抑制某条规则(慎用)
      • 9. 与 `set` 选项
      • 10. 工作流建议
      • 11. ShellCheck 不能发现什么
    • 读脚本检查清单
    • 练习
      • 判断题
      • 实操题
      • 改错题
    • 下一篇预告

本篇目标

会用ShellCheck不运行脚本的情况下发现引号、set、管道、可移植性等问题。能读懂SC 编号提示、用shellcheck命令与编辑器集成,并知道何时该改、何时可 disable。专栏其它篇不写 SC 小节;本篇集中讲工具(与 S12-01 动态-x互补)。


30 秒速览

  • bash -n:只查语法,不查逻辑与引号坑。
  • ShellCheck:静态分析,报SCxxxx编号与说明。
  • 安装:apt install shellcheckbrew install shellcheck,或 shellcheck.net。
  • 常用:shellcheck script.sh;指定 shell:-s bash;跟踪source-x
  • 高频 SC:2086未引号变量、2164cd失败、2181误用$?2046命令替换未引号。
  • disable要有理由;不要为消警告而乱关检查。

正文

1. 静态检查 vs 动态调试

手段何时本篇 / 篇目
ShellCheck保存/提交前S12-02
set -x运行结果不对S12-01
最小复现仍不清楚S12-03
shellcheckdeploy.sh

不执行脚本,只分析文本。


2.bash -n:仅语法

bash-nscript.sh
  • 发现if未闭合引号不配解析错误
  • 发现未引号变量、set -u风险、管道逻辑问题

习惯bash -n+ ShellCheck一起用。


3. 安装与基本用法

# Debian/Ubuntusudoaptinstallshellcheck# macOSbrewinstallshellcheck# 检查单文件shellcheckdeploy.sh# 明确按 Bash 规则(推荐本专栏脚本)shellcheck-sbashdeploy.sh# 跟踪 source 路径(分析被 source 的库)shellcheck-x-sbashmain.sh

在线:把脚本贴到shellcheck.net(勿贴含密钥的产线脚本)。


4. 输出长什么样

deploy.sh:12:8: warning: Double quote to prevent globbing and word splitting. [SC2086] rm -f $tmp ^--^
部分含义
行:列位置
warning/error/info/style严重级别
SC2086规则编号(可查 wiki)
下文说明与建议

严重级别

级别建议
error尽量修
warning多数应修
info/style视团队规范

5. 高频 SC 与专栏篇目对照

读 ShellCheck 报告时,可联想到专栏哪篇讲过:

SC典型提示专栏
SC2086变量应双引号S02-01、S02-03
SC2046$(cmd)结果应引号S09-03、S07-01
SC2068"$@"应引号S03-03
SC2164cd dir失败未处理S05-02、S11-02
SC2181if cmd别只看$?S04-01
SC2006$( )别用反引号S09-03
SC2154变量未赋值就引用S03-01、set -uS01-04
SC2155local var=$(cmd)掩码退出码S08-02
SC2034变量「未使用」可能误报(export、read)
SC1090无法跟踪source非常量路径S08-03
SC3043pipefailsh不可用S13 可移植
SC2015set -eA && B || C注意S04-02

6. 示例:改前 / 改后

6.1 SC2086
# 警告rm-f$tmp# 修复rm-f--"$tmp"
6.2 SC2164
# 警告cd"$dir"do_work# 修复cd"$dir"||exit1do_work
6.3 SC2181
# 警告mycmdif[[$?-eq0]];then...# 修复ifmycmd;then...
6.4 SC2046
# 警告forfin$(ls*.log);do# 更好(专栏 S07-01)forfin*.log;do

7.source与 SC1090

source"${SCRIPT_DIR}/lib/common.sh"

ShellCheck 可能报SC1090(无法解析非常量 source)。处理:

# 分析主脚本时跟踪 sourceshellcheck-x-sbashmain.sh# 或单独检查库shellcheck-sbashlib/common.sh

读脚本:SC1090 不是运行时错误,是静态分析范围限制。


8. 抑制某条规则(慎用)

# 单行# shellcheck disable=SC2034UNUSED_FOR_EXPORT=1# 下一行# shellcheck disable=SC2086eval"legacy_code"# 仅当确知安全且有注释说明

原则

  • 先修再 disable
  • disable 旁写原因
  • 不要disable=SC2086整文件

9. 与set选项

ShellCheck 理解常见写法,会提示:

  • set -ecmd && cmd || other组合(SC2015)
  • set -u与未定义变量
  • set -o pipefail#!/bin/sh脚本(SC3043)
#!/bin/shset-opipefail# SC3043:POSIX sh 未必支持

→ 改shebang 为 bash或去掉 pipefail(S13)。


10. 工作流建议

阶段动作
编辑时VS Code/CursorShellCheck 扩展波浪线
提交前shellcheck -s bash *.sh
CI流水线跑 shellcheck,error 失败
排错时ShellCheck 通过后仍用S12-01-x
findscripts-name'*.sh'-print0|xargs-0shellcheck-sbash

11. ShellCheck 不能发现什么

  • 业务逻辑错(删错文件但语法对)
  • 运行时网络/权限
  • 复杂依赖顺序
  • 所有可移植性(需 S13 + 多环境测)

静态 + 运行结合。


读脚本检查清单

  • 仓库是否约定ShellCheck/ CI?
  • 报告SC2086/2046是否已修引号?
  • SC2164cd是否|| exit
  • disable是否有注释理由?
  • shebang 与-s bash是否一致?

练习

判断题

  1. bash -n能发现$var未加引号的风险。
  2. SC2086 通常建议给变量加双引号。
  3. shellcheck -s bash按 Bash 规则分析。
  4. SC1090 表示 source 的文件一定不存在。
  5. 专栏只在 S12-02 集中讲 SC 编号,其它篇用通用表述。
参考答案
  1. 错。
  2. 对。
  3. 对。
  4. 错(常是静态分析跟不进动态路径)。
  5. 对(本篇为工具专篇)。

实操题

对下面片段,说出 ShellCheck最可能报哪类 SC(不必跑工具):

tmp=$(mktemp)cd$tmpdirrm-f$tmp
参考答案
  • SC2086$tmpdir$tmp未引号。
  • SC2164cd|| exit
  • tmpdir未定义还有SC2154(set -u 运行时也会炸)。

改错题

#!/usr/bin/env bashset-efiles=$(ls*.log)forfin$files;dogreppattern$f|wc-ldone
参考
#!/usr/bin/env bashset-euopipefailshopt-snullglobforfin*.log;dogrep-Fpattern --"$f"|wc-ldone

消除SC2046/2086/2006类问题;grep字面用-Fpipefail按需。


下一篇预告

S12-03:《排错方法论:最小复现与二分定位》— 完成 S12 模块,练「读一段卡住的脚本」。

http://www.jsqmd.com/news/1159715/

相关文章:

  • ClawdBot:轻量级自动化代理框架实现7×24数字分身
  • 大模型自检机制:提升LLM输出可靠性的工程实践
  • C++ 操作 Word 文档 2 大方案对比:COM自动化 vs 第三方库(Aspose.Words)
  • 实用AI教程:从RAG构建到模型部署的工程实践指南
  • 计算机毕业设计之社区居家养老服务系统
  • 工业级负载控制方案:TPD2015FN与PIC18LF4525应用解析
  • 大数据毕设项目:基于 Django 的 IT 岗位供需平衡分析系统的设计与实现 基于 Django 的简历特征匹配招聘推荐系统 (源码+文档,讲解、调试运行,定制等)
  • COMSOL 6.0 固化反应接口实战:3步耦合热-化-力分析树脂变形
  • GEO系统实战:破解流量瓶颈与去中心化发布
  • vLLM 与 SGLang 推理框架性能横评:吞吐、延迟与成本深度剖析
  • CTF实战:ECDSA随机数重用漏洞分析与私钥破解
  • PCA / t-SNE / UMAP 极简可视化选型手册
  • 百度网盘提取码一键获取终极指南:告别繁琐搜索,5秒直达资源
  • Pytest参数化实战:接口自动化测试数据驱动与工程化实践
  • 开源免费!3步搞定Windows视频播放难题的LAV Filters终极方案
  • 湖北省世达实用外国语学校商务英语出国留学专业招生简章 - 湖北找学校
  • Cocos Creator入门:从零构建首个2D游戏项目实践指南
  • 参考 Claude Tag 设计:用 Claude API 实现团队级场景隔离、记忆边界与预算控制
  • SPICE 仿真器核心:MNA 处理电压源与非线性元件的 2 类方程分组策略
  • 小米账号解锁限制分析:1月1台与1年4台的策略解读与 2 种应对思路
  • 为什么不建议从零开发商城?只因我们靠开源商城省下了60%的研发成本
  • OpenClaw 2.6.4 Windows 安装与配置全指南
  • 专业的运营策划哪家好?四个核心维度筛选靠谱机构
  • STM32步进电机控制:20秒实现A4988驱动与精准时序
  • Windows智能体开发实战:从API调用到能力集成的系统级Agent构建
  • NCM解密终极指南:3分钟解锁你的网易云音乐收藏
  • 2026兰州冰块品牌Top榜:工业降温大冰块实力推荐! - 热点咨讯
  • Hugging Face Transformers 加载模型报错 NameError: 5种 torch 导入陷阱排查
  • 彻底解决Windows系统VCRUNTIME140.dll等VC++运行时库缺失问题
  • 靶向matCAF药物筛选:基于分子对接与小鼠模型验证PCC1抑制肿瘤生长的3步策略