用途
ShellCheck 是一个静态分析工具,用于分析 Shell 脚本并检测有问题的模式。本技能提供配置和使用 ShellCheck 的全面指导,帮助改进 Shell 脚本质量、捕获常见陷阱,并通过静态代码分析强制执行最佳实践。
适用场景包括:
- 在 CI/CD 流水线中为 Shell 脚本搭建 lint 检查
- 分析现有 Shell 脚本中的问题
- 理解 ShellCheck 错误码和警告
- 针对特定项目需求配置 ShellCheck
- 将 ShellCheck 集成到开发工作流中
- 抑制误报并配置规则集
- 强制执行一致的代码质量标准
- 迁移脚本以满足质量门禁
主要能力
ShellCheck 支持 Bash、sh、dash、ksh 及其他 POSIX shell,提供超过 100 种警告和错误,可配置目标 shell 和标志,并能与编辑器和 CI/CD 系统集成。
安装
# macOS with Homebrew
brew install shellcheck
# Ubuntu/Debian
apt-get install shellcheck
# From source
git clone https://github.com/koalaman/shellcheck.git
cd shellcheck
make build
make install
# Verify installation
shellcheck --version
配置文件
项目级 .shellcheckrc(放在项目根目录):
# Specify target shell
shell=bash
# Enable optional checks
enable=avoid-nullary-conditions
enable=require-variable-braces
# Disable specific warnings
disable=SC1091
disable=SC2086
环境变量:
# Set default shell target
export SHELLCHECK_SHELL=bash
# Enable strict mode
export SHELLCHECK_STRICT=true
# Specify configuration file location
export SHELLCHECK_CONFIG=~/.shellcheckrc
常见错误码
- SC1000-1099:解析器错误,如 SC1004(反斜杠续行后未换行)、SC1008(
==运算符数据无效)。 - SC2000-2099:Shell 问题,如 SC2009(建议用 pgrep 或 pidof 替代 grep|grep)、SC2012(
ls仅用于查看,可靠输出用find)、SC2015(避免用&&和||替代 if-then-else)、SC2016(单引号内表达式不展开)。 - SC2100-2199:引用问题,如 SC2086(双引号防止通配和分词)、SC2115(路径中的字面量波浪号不展开,改用
$HOME)、SC2181(直接用if检查退出码)、SC2206(引用防止分词或设置 IFS)。 - SC3000-3999:POSIX 合规问题,如 SC3010(POSIX sh 中用
case替代cond && foo)、SC3043(POSIX sh 中local未定义)。
使用方式
配置示例
最小配置(严格 POSIX):
shellcheck \
--shell=sh \
--external-sources \
--check-sourced \
script.sh
开发配置(Bash 宽松规则):
shellcheck \
--shell=bash \
--exclude=SC1091,SC2119 \
--enable=all \
script.sh
CI/CD 集成配置:
set -Eeuo pipefail
find . -type f -name "*.sh" | while read -r script; do
echo "Checking: $script"
shellcheck \
--shell=bash \
--format=gcc \
--exclude=SC1091 \
"$script" || exit 1
done
项目 .shellcheckrc:
shell=bash
enable=avoid-nullary-conditions,require-variable-braces,check-unassigned-uppercase
disable=SC1091
disable=SC2119
external-sources=true
集成模式
Pre-commit 钩子(.git/hooks/pre-commit):
set -e
git diff --cached --name-only | grep '\.sh$' | while read -r script; do
echo "Linting: $script"
if ! shellcheck "$script"; then
echo "ShellCheck failed on $script"
exit 1
fi
done
GitHub Actions 工作流:
name: ShellCheck
on: [push, pull_request]
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run ShellCheck
run: |
sudo apt-get install shellcheck
find . -type f -name "*.sh" -exec shellcheck {} \;
GitLab CI 流水线:
shellcheck:
stage: lint
image: koalaman/shellcheck-alpine
script:
- find . -type f -name "*.sh" -exec shellcheck {} \;
allow_failure: false
处理违规
抑制特定警告:
# Disable warning for entire line
# shellcheck disable=SC2086
for file in $(ls -la); do
echo "$file"
done
# Disable for entire script
# shellcheck disable=SC1091,SC2119
# Disable specific check for source directive
# shellcheck source=./helper.sh
source helper.sh
常见违规修复:
- SC2086:
for i in $list; do done改为for i in "${list[@]}"; do done(若为数组)。 - SC2181:
some_command; if [ $? -eq 0 ]; then改为if some_command; then。 - SC2015:
[ -f "$file" ] && echo "exists" || echo "not found"改为 if-then-else。 - SC2016:
echo 'Variable value: $VAR'改为echo "Variable value: $VAR"。 - SC2009:
ps aux | grep -v grep | grep myprocess改为pgrep -f myprocess。
性能优化
并行检查:
find . -name "*.sh" -print0 | \
xargs -0 -P 4 -n 1 shellcheck
缓存结果:
CACHE_DIR=".shellcheck_cache"
mkdir -p "$CACHE_DIR"
check_script() {
local script="$1"
local hash
local cache_file
hash=$(sha256sum "$script" | cut -d' ' -f1)
cache_file="$CACHE_DIR/$hash"
if [[ ! -f "$cache_file" ]]; then
if shellcheck "$script" > "$cache_file" 2>&1; then
touch "$cache_file.ok"
else
return 1
fi
fi
[[ -f "$cache_file.ok" ]]
}
find . -name "*.sh" | while read -r script; do
check_script "$script" || exit 1
done
输出格式
- 默认格式:
shellcheck script.sh,输出如script.sh:1:3: warning: foo is referenced but not assigned. [SC2154]。 - GCC 格式(用于 CI/CD):
shellcheck --format=gcc script.sh。 - JSON 格式(用于解析):
shellcheck --format=json script.sh。 - 安静格式:
shellcheck --format=quiet script.sh,发现问题返回非零,否则无输出。
适用场景
- 在 CI/CD 中运行 ShellCheck,在合并前捕获问题
- 针对目标 shell 进行配置,避免将 bash 当作 sh 分析
- 记录排除项,解释为何抑制违规
- 解决违规而非仅禁用警告
- 启用严格模式,使用
--enable=all并谨慎排除 - 定期更新 ShellCheck 以获取新检查
- 使用 pre-commit 钩子在推送前本地捕获问题
- 与编辑器集成,在开发过程中获得实时反馈
限制
资料未提供 ShellCheck 的收费、价格、平台限制或具体效果数据。部分错误码示例中的修复建议在原文中未完整给出,实际使用时请参考 ShellCheck 官方 Wiki 和错误码参考。
资源
- ShellCheck GitHub:https://github.com/koalaman/shellcheck
- ShellCheck Wiki:https://www.shellcheck.net/wiki/
- 错误码参考:https://www.shellcheck.net/