ShellCheck

← 返回目录 > ← 返回总览

相关工具推荐

工具 说明
Shfmt Shell 脚本格式化工具
Pre-commit Git 提交门禁框架

1. 简介

ShellCheck 是 Shell/Bash 脚本的静态分析工具,由 Vidar Holen 创建并维护,采用 GPLv3 许可证发布,使用 Haskell 语言编写。它能够检测 Shell 脚本中的语法错误、语义问题、典型陷阱和代码风格问题,并为每条告警提供详细的修复建议和 Wiki 文档链接。

  • 主要检查语言:Shell(Bash、dash、ksh)
  • 主要检查能力:对 sh/bash/dash/ksh 脚本进行静态分析,检测语法错误、语义缺陷、兼容性问题和代码异味;涵盖质量类检查(语法错误、语义缺陷)+ 风格类检查(代码风格建议)+ 兼容性检查(POSIX 可移植性)
  • 核心检查原理:基于 Shell AST 分析
  • 检查规则/选项:约 280+ 条 SC 规则(SC1000–SC2236,每条规则有独立 wiki 页面),全量规则列表
  • GitHub 仓库https://github.com/koalaman/shellcheck(39,560 stars)
  • 开源协议:GPL-3.0-or-later
  • 最新稳定版本:v0.10.0
  • 运行环境要求:无(独立二进制)
  • 误报率:低

ShellCheck 是 Shell 脚本静态分析领域的主流工具之一,在 DevOps 和基础设施自动化项目中被广泛采用。


2. 官方文档

资源 链接 说明
GitHub 仓库 https://github.com/koalaman/shellcheck 源码、Issue、Release
在线检查 https://www.shellcheck.net 在线 Web 版本
规则 Wiki https://www.shellcheck.net/wiki/ 所有检查规则的完整索引
集成文档 https://github.com/koalaman/shellcheck/wiki/Integration 输出格式、退出码、环境变量等集成说明
手册页源文件 https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md 命令行参数、指令、RC 文件等完整参考
Release 下载 https://github.com/koalaman/shellcheck/releases 各平台预编译二进制文件

3. 社区优秀实践

3.1 ShellCheck 官方 pre-commit 钩子仓库

ShellCheck 官方维护了独立的 pre-commit 钩子仓库 koalaman/shellcheck-precommit,使用 Docker 镜像运行 ShellCheck,确保版本一致性。该仓库的 .pre-commit-hooks.yaml 定义了官方 hook 配置。

  • 仓库地址https://github.com/koalaman/shellcheck-precommit
  • 实践要点
    • 使用 language: docker_image,通过 Docker 容器运行 ShellCheck,无需本地安装
    • hook 类型默认匹配 types: [shell],自动识别 Shell 脚本文件
    • 版本与 ShellCheck release 同步更新(当前 v0.11.0)

3.2 Homebrew

Homebrew 是 macOS 和 Linux 上主流的包管理器之一,其核心仓库 Homebrew/brew 包含大量 Shell 脚本。Homebrew 在 CI 流水线中使用 ShellCheck 对 Shell 脚本进行质量检查。

3.3 VS Code ShellCheck 扩展

vscode-shellcheck 是 ShellCheck 在 VS Code 中的官方推荐扩展,由社区维护,内置了多平台 ShellCheck 二进制文件,开箱即用。

  • 仓库地址https://github.com/timonwong/vscode-shellcheck
  • 实践要点
    • 内置 Linux(x86_64/arm64/arm)、macOS(x86_64/arm64)、Windows(x86_64/arm64)的 ShellCheck 二进制
    • 支持 onType(实时)和 onSave(保存时)两种检查模式
    • 支持 source.fixAll.shellcheck 自动修复
    • 通过 .shellcheckrc 项目配置文件进行规则定制

4. 工具配置说明

4.1 配置文件说明

ShellCheck 支持多层级的配置方式,优先级从高到低为:源码内联指令 > 命令行参数 > RC 配置文件

ShellCheck 涉及以下配置文件:

配置文件 用途 使用场景
.shellcheckrc ShellCheck RC 配置文件(INI 格式),声明 Shell 方言、告警级别、排除规则、启用可选检查等 所有项目,控制检查行为

配置文件查找顺序

  1. 命令行 --norc 选项可跳过所有 RC 文件
  2. 命令行 --rcfile 指定的文件
  3. 脚本所在目录及逐级父目录中的 .shellcheckrcshellcheckrc
  4. ~/.shellcheckrc
  5. $XDG_CONFIG_HOME/shellcheckrc(通常为 ~/.config/shellcheckrc

4.2 .shellcheckrc 配置详解

.shellcheckrc 是 ShellCheck 的 RC 配置文件,ShellCheck 会自动从脚本所在目录逐级向上查找,然后查找 ~/.shellcheckrc$XDG_CONFIG_HOME/shellcheckrc

配置项说明

配置项 类型 说明
shell string 指定 Shell 方言(如 bashshdashksh
severity string 最低告警级别(errorwarninginfostyle),低于此级别的告警被忽略
exclude list[string] 排除的规则编号列表,逗号分隔(如 SC1090,SC1091
external-sources bool 是否跟踪 source 引用的外部文件(默认 false)
source-path list[string] 外部文件的搜索路径列表(如 SCRIPTDIRlib
enable list[string] 启用的可选检查列表,逗号分隔(如 add-default-case,check-unassigned-uppercase

推荐配置示例

基础配置(适用于大多数 Shell 脚本项目):在保持合理检查覆盖的同时避免过多噪音。

# .shellcheckrc - ShellCheck 基础配置

# 指定 Shell 方言为 Bash
# 说明:确保检查规则基于 Bash 语法,避免 POSIX 兼容性误报
shell=bash

# 设置最低告警级别为 warning
# 说明:忽略 info 和 style 级别的建议,仅报告 warning 和 error
severity=warning

# 跟踪 source 引用的外部文件
# 说明:避免 SC1090(无法跟踪 source)和 SC1091(无法打开文件)误报
external-sources=true

# 排除动态 source 文件路径相关的规则
# SC1090: 无法跟踪动态 source 路径(如 source "$DIR/lib.sh")
# SC1091: 无法打开被 source 的文件进行检查
# 说明:动态路径在静态分析时无法解析,通常需要运行时上下文
exclude=SC1090,SC1091

严格配置(适用于生产环境脚本、基础设施自动化等对质量要求极高的场景):

# .shellcheckrc - ShellCheck 严格配置

# 指定 Shell 方言为 Bash
shell=bash

# 设置最低告警级别为 style(最低级别,报告所有问题)
severity=style

# 跟踪 source 引用的外部文件
external-sources=true

# 指定外部文件的搜索路径
# 说明:帮助 ShellCheck 找到被 source 的文件
source-path=SCRIPTDIR
source-path=lib

# 启用可选检查
# add-default-case: 建议 switch/case 语句添加 default 分支
# check-unassigned-uppercase: 检查未赋值的大写变量(可能为环境变量)
# quote-safe-variables: 对已知安全值的未引用变量发出警告
enable=add-default-case,check-unassigned-uppercase,quote-safe-variables

# 排除特定规则
# SC1090: 无法跟踪动态 source 路径
# SC1091: 无法打开被 source 的文件
exclude=SC1090,SC1091

4.3 常用规则编号速查

规则编号 严重级别 说明 修复建议
SC2086 warning 变量未加双引号,可能导致单词拆分和通配符展开 使用 "$var" 替代 $var
SC2181 error 使用 $? 检查退出码,而非直接检查命令 使用 if ! cmd; then ... 替代 cmd; if [ $? -ne 0 ]
SC2006 info 使用反引号执行命令 使用 $(cmd) 替代 `cmd`
SC2003 info 使用过时的 expr 命令 使用 $((..))${} 替代
SC2164 error cd 命令未检查退出状态 使用 `cd dir
SC2034 info 变量已赋值但未使用 检查变量名拼写或删除未使用的变量
SC2154 warning 变量被引用但未赋值 检查变量名拼写或添加赋值语句
SC1090 info 无法跟踪动态 source 路径 添加 # shellcheck source=/path/to/file 注释
SC1091 info 无法打开被 source 的文件 确保 --external-sources--source-path 配置正确
SC2317 warning 命令看似不可达(可能被间接调用) 使用 # shellcheck disable=SC2317 屏蔽
SC2115 error 使用 rm -rf 删除可能为空的变量路径 添加路径非空检查
SC1045 error if 条件表达式语法错误 检查 [ 后是否有空格
SC2066 warning for 循环中错误使用双引号导致只迭代一次 移除变量外的双引号或使用数组
SC2016 info 单引号中的表达式不会被展开 使用双引号 "..." 替代单引号 '...'

所有规则的完整列表和详细说明请参考:https://www.shellcheck.net/wiki/


5. 主流集成方式

5.1 pre-commit 集成

ShellCheck 官方提供了独立的 pre-commit 钩子仓库,使用 Docker 镜像运行,适合作为本地提交门禁。

依赖来源与适用前提

  • 使用 language: docker_image,需要系统安装 Docker
  • 无需本地安装 ShellCheck,由 Docker 镜像提供
  • pre-commit 框架默认仅将暂存区中变更文件传给 hook,天然支持增量检查

配置文件.pre-commit-config.yaml):

repos:
  - repo: https://github.com/koalaman/shellcheck-precommit
    rev: v0.10.0
    hooks:
      - id: shellcheck
        # 可选:仅显示 error 和 warning 级别
        # args: ["--severity=warning"]

使用本地 ShellCheck(无需 Docker)

如果不想依赖 Docker,可以使用 language: system 配置,前提是系统已安装 ShellCheck:

repos:
  - repo: https://github.com/koalaman/shellcheck-precommit
    rev: v0.10.0
    hooks:
      - id: shellcheck
        language: system

注意:将 language 改为 system 后,hook 将使用系统 PATH 中的 ShellCheck,需确保已安装且版本兼容。

增量检查:pre-commit 框架默认仅将暂存区中变更文件传给 hook,天然实现文件级增量检查,无需额外配置。CI 中可通过 pre-commit run --all-files 做全量检查,或使用 --from-ref/--to-ref 做 PR 级增量。

5.2 IDE 集成

VS Code

安装扩展 timonwong.shellcheck,内置多平台 ShellCheck 二进制,开箱即用。

配置示例.vscode/settings.json):

{
  "shellcheck.enable": true,
  "shellcheck.executablePath": "",
  "shellcheck.exclude": [],
  "shellcheck.customArgs": [],
  "shellcheck.run": "onType",
  "shellcheck.ignorePatterns": {
    "**/*.zsh": true,
    "**/*.zshrc": true
  }
}
配置项 说明
shellcheck.enable 是否启用(默认 true
shellcheck.executablePath ShellCheck 路径(默认使用内置二进制)
shellcheck.exclude 排除的规则编号列表
shellcheck.customArgs 自定义命令行参数
shellcheck.run 触发时机:onType / onSave

保存时自动修复:

{
  "editor.codeActionsOnSave": {
    "source.fixAll.shellcheck": "explicit"
  }
}

Vim / Neovim

通过 ALE(异步 Lint 引擎)集成 ShellCheck:

" ~/.vimrc 或 ~/.config/nvim/init.vim
Plug 'dense-analysis/ale'

let g:ale_linters = {
\   'sh': ['shellcheck'],
\   'bash': ['shellcheck']
\}
let g:ale_sh_shellcheck_options = '--shell=bash --external-sources'

其他方案:NeomakeSyntastic 也支持 ShellCheck。

Emacs

通过 FlycheckFlymake 集成。

Sublime Text

通过 SublimeLinter-shellcheck 集成。

5.3 命令行使用方式

常用命令

# 检查单个文件
shellcheck script.sh

# 检查多个文件
shellcheck script1.sh script2.sh

# 从标准输入读取
cat script.sh | shellcheck -

# 从文件列表读取
shellcheck --files-from=scriptlist.txt

常用参数

# 指定 Shell 方言(sh/bash/dash/ksh)
shellcheck -s bash script.sh

# 设置最低告警级别(error/warning/info/style)
shellcheck --severity=warning script.sh

# 排除特定规则
shellcheck --exclude=SC2086,SC1090 script.sh

# 仅包含特定规则
shellcheck --include=SC2086,SC2181 script.sh

# 跟踪 source 引用的外部文件
shellcheck --external-sources script.sh

# 指定外部文件的搜索路径
shellcheck --source-path=lib:scripts script.sh

# 启用可选检查
shellcheck --enable=add-default-case script.sh

# 启用所有可选检查
shellcheck --enable=all script.sh

# 不加载 RC 配置文件
shellcheck --norc script.sh

输出格式

# 默认 TTY 格式(人类可读)
shellcheck script.sh

# GCC 兼容格式(适用于编辑器集成)
shellcheck -f gcc script.sh

# CheckStyle XML 格式(适用于 CI 工具)
shellcheck -f checkstyle script.sh

# JSON 格式(适用于程序化处理)
shellcheck -f json1 script.sh

# diff 格式(可应用自动修复)
shellcheck -f diff script.sh

增量检查:ShellCheck 没有内置增量参数,可结合 git diff 筛选变更文件后传递给 shellcheck:

# 仅检查暂存区(staged)中新增或修改的 .sh 文件
git diff --cached --name-only --diff-filter=ACMR -- '*.sh' | xargs shellcheck

# 仅检查相对于 HEAD 变更的 .sh 文件
git diff --name-only --diff-filter=ACMR HEAD -- '*.sh' | xargs shellcheck

# 仅检查工作区中修改的 .sh 文件
git diff --name-only --diff-filter=ACMR -- '*.sh' | xargs shellcheck

--diff-filter=ACMR 表示仅包含新增(A)、复制(C)、修改(M)、重命名(R)的文件,排除删除的文件。

此外,ShellCheck 提供了 --files-from 参数(v0.10.0 新增),可以从文件中读取待检查的文件列表,便于与外部脚本配合实现增量检查:

# 生成变更文件列表,然后通过 --files-from 传入
git diff --cached --name-only --diff-filter=ACMR -- '*.sh' > /tmp/files.txt
shellcheck --files-from=/tmp/files.txt

CI 脚本调用:在 CI 环境中通过脚本调用 ShellCheck 进行检查。

GitHub Actions

方式一:使用系统包管理器

name: ShellCheck
on: [push, pull_request]
jobs:
  shellcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run ShellCheck
        run: |
          sudo apt-get update && sudo apt-get install -y shellcheck
          find . -name '*.sh' -not -path './vendor/*' \
            -exec shellcheck --severity=warning {} +

方式二:使用预编译二进制(锁定版本)

name: ShellCheck
on: [push, pull_request]
jobs:
  shellcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Download ShellCheck
        run: |
          wget -qO- https://github.com/koalaman/shellcheck/releases/download/v0.10.0/shellcheck-v0.10.0.linux.x86_64.tar.xz \
            | tar -xJv
          sudo mv shellcheck-v0.10.0/shellcheck /usr/local/bin/
      - name: Run ShellCheck
        run: shellcheck --severity=warning scripts/*.sh

GitLab CI

shellcheck:
  stage: lint
  image: koalaman/shellcheck-alpine:stable
  script:
    - shellcheck --severity=warning scripts/*.sh
  rules:
    - changes:
        - "**/*.sh"

注意:koalaman/shellcheck-alpine 是 ShellCheck 官方提供的 Alpine Linux 基础镜像,预装 ShellCheck。

增量检查:GitHub Actions 中可仅对变更文件运行 ShellCheck:

- name: Run ShellCheck on changed files
  run: |
    git diff --name-only --diff-filter=d ${{ github.event.before }}...${{ github.event.after }} \
      | grep '\.sh$' \
      | xargs shellcheck --severity=warning

GitLab CI 中按 MR 变更文件触发增量检查:

shellcheck:
  stage: lint
  image: koalaman/shellcheck-alpine:stable
  script:
    - git diff --name-only --diff-filter=d $CI_MERGE_REQUEST_DIFF_BASE_SHA...HEAD -- '*.sh' | xargs shellcheck --severity=warning
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

5.4 包管理器安装(生态主流)

ShellCheck 的主要安装方式是通过系统包管理器或预编译二进制,这是 Shell 生态中最主流的方式。

# macOS
brew install shellcheck

# Debian/Ubuntu
sudo apt install shellcheck

# Fedora
dnf install ShellCheck

# Arch Linux
pacman -S shellcheck

# Windows (winget)
winget install --id koalaman.shellcheck

# Windows (scoop)
scoop install shellcheck

# Docker
docker run --rm -v "$PWD:/mnt" koalaman/shellcheck:stable myscript

# Nix
nix-env -iA nixpkgs.shellcheck

预编译二进制可从 GitHub Releases 下载,支持 Linux(x86_64/armv6hf/aarch64/riscv64)、macOS(x86_64/aarch64)、Windows(x86)。


6. 告警抑制(屏蔽)方法

6.1 通过源码内联注释屏蔽

通过在 Shell 脚本中添加 # shellcheck 指令来屏蔽特定规则。指令放在第一个命令之前为文件级,放在命令之前为该命令级。

行级屏蔽

# shellcheck disable=SC2086
echo $VAR

块级屏蔽(屏蔽多行):

# shellcheck disable=SC2086,SC2034
echo $VAR
UNUSED_VAR="hello"
# shellcheck enable=SC2086,SC2034

函数级屏蔽

# shellcheck disable=SC2317
start() {
    echo "Starting"
    /etc/init.d/foo start
}

文件级屏蔽(放在 shebang 之后、任何命令之前):

#!/bin/bash
# shellcheck disable=SC2086,SC2034,SC2317
echo $VAR

官方文档:Directives(shellcheck.1.md)

6.2 通过 RC 配置文件屏蔽

.shellcheckrc 中通过 disable 字段全局排除特定规则:

# .shellcheckrc
disable=SC2086,SC1090,SC1091,SC2034

官方文档:RC Files(shellcheck.1.md)

6.3 通过命令行参数屏蔽

# 排除特定规则
shellcheck --exclude=SC2086,SC1090 script.sh

# 设置最低告警级别(低于该级别的告警全部屏蔽)
shellcheck --severity=error script.sh

--severity 的有效值(按严重程度从高到低):error > warning > info > style

官方文档:OPTIONS(shellcheck.1.md)

6.4 通过 pre-commit 框架屏蔽

通过 pre-commit 的 filesexclude 参数控制 hook 作用的文件范围:

repos:
  - repo: https://github.com/koalaman/shellcheck-precommit
    rev: v0.10.0
    hooks:
      - id: shellcheck
        # 仅检查 .sh 文件
        files: \.sh$
        # 排除 vendor 目录
        exclude: ^vendor/

官方文档:pre-commit 配置

6.5 通过 VS Code 扩展屏蔽

settings.json 中配置排除规则:

{
  "shellcheck.exclude": ["SC1090", "SC1091"]
}

或通过 shellcheck.ignorePatterns 忽略特定文件:

{
  "shellcheck.ignorePatterns": {
    "**/*.zsh": true,
    "**/vendor/**/*.sh": true
  }
}

官方文档:vscode-shellcheck README

6.6 各方式对比

屏蔽方式 适用场景 粒度 持久性 官方文档
源码内联注释 需要解释为何屏蔽时 行/块/函数/文件 随代码提交 Directives
RC 配置文件 项目级全局排除 项目/目录 随项目配置 RC Files
命令行参数 临时调试或 CI 定制 单次执行 仅当次运行 OPTIONS
pre-commit 配置 控制 hook 作用范围 文件匹配模式 随项目配置 pre-commit 配置
VS Code 设置 开发者个人偏好 工作区/用户 随 IDE 设置 vscode-shellcheck

← 返回目录 | ← 返回总览