shellcheck-configuration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ShellCheck Configuration and Static Analysis

ShellCheck 配置与静态分析

Comprehensive guidance for configuring and using ShellCheck to improve shell script quality, catch common pitfalls, and enforce best practices through static code analysis.
本文提供配置和使用ShellCheck的全面指南,通过静态代码分析提升Shell脚本质量、排查常见问题并践行最佳实践。

When to Use This Skill

适用场景

  • Setting up linting for shell scripts in CI/CD pipelines
  • Analyzing existing shell scripts for issues
  • Understanding ShellCheck error codes and warnings
  • Configuring ShellCheck for specific project requirements
  • Integrating ShellCheck into development workflows
  • Suppressing false positives and configuring rule sets
  • Enforcing consistent code quality standards
  • Migrating scripts to meet quality gates
  • 在CI/CD流水线中为Shell脚本搭建代码检查机制
  • 分析现有Shell脚本中的问题
  • 理解ShellCheck错误码与警告信息
  • 根据项目需求配置ShellCheck
  • 将ShellCheck集成到开发工作流中
  • 抑制误报并配置规则集
  • 推行一致的代码质量标准
  • 迁移脚本以满足质量要求

ShellCheck Fundamentals

ShellCheck 基础

What is ShellCheck?

什么是ShellCheck?

ShellCheck is a static analysis tool that analyzes shell scripts and detects problematic patterns. It supports:
  • Bash, sh, dash, ksh, and other POSIX shells
  • Over 100 different warnings and errors
  • Configuration for target shell and flags
  • Integration with editors and CI/CD systems
ShellCheck是一款静态分析工具,用于分析Shell脚本并检测有问题的代码模式。它支持:
  • Bash、sh、dash、ksh及其他POSIX兼容Shell
  • 超过100种不同的警告与错误类型
  • 针对目标Shell和参数的配置
  • 与编辑器及CI/CD系统的集成

Installation

安装方法

bash
undefined
bash
undefined

macOS with Homebrew

macOS 系统使用 Homebrew

brew install shellcheck
brew install shellcheck

Ubuntu/Debian

Ubuntu/Debian 系统

apt-get install shellcheck
apt-get install shellcheck

From source

从源码编译安装

git clone https://github.com/koalaman/shellcheck.git cd shellcheck make build make install
git clone https://github.com/koalaman/shellcheck.git cd shellcheck make build make install

Verify installation

验证安装

shellcheck --version
undefined
shellcheck --version
undefined

Configuration Files

配置文件

.shellcheckrc (Project Level)

.shellcheckrc(项目级配置)

Create
.shellcheckrc
in your project root:
undefined
在项目根目录创建
.shellcheckrc
文件:
undefined

Specify target shell

指定目标Shell

shell=bash
shell=bash

Enable optional checks

启用可选检查规则

enable=avoid-nullary-conditions enable=require-variable-braces
enable=avoid-nullary-conditions enable=require-variable-braces

Disable specific warnings

禁用特定警告

disable=SC1091 disable=SC2086
undefined
disable=SC1091 disable=SC2086
undefined

Environment Variables

环境变量配置

bash
undefined
bash
undefined

Set default shell target

设置默认目标Shell

export SHELLCHECK_SHELL=bash
export SHELLCHECK_SHELL=bash

Enable strict mode

启用严格模式

export SHELLCHECK_STRICT=true
export SHELLCHECK_STRICT=true

Specify configuration file location

指定配置文件位置

export SHELLCHECK_CONFIG=~/.shellcheckrc
undefined
export SHELLCHECK_CONFIG=~/.shellcheckrc
undefined

Common ShellCheck Error Codes

常见ShellCheck错误码

SC1000-1099: Parser Errors

SC1000-1099:解析器错误

bash
undefined
bash
undefined

SC1004: Backslash continuation not followed by newline

SC1004:反斜杠续行后未换行

echo hello
world # Error - needs line continuation
echo hello
world # 错误 - 需要正确的换行续行

SC1008: Invalid data for operator `=='

SC1008:运算符
==
使用无效数据

if [[ $var = "value" ]]; then # Space before == true fi
undefined
if [[ $var = "value" ]]; then # == 前存在多余空格 true fi
undefined

SC2000-2099: Shell Issues

SC2000-2099:Shell相关问题

bash
undefined
bash
undefined

SC2009: Consider using pgrep or pidof instead of grep|grep

SC2009:建议使用 pgrep 或 pidof 替代 grep|grep

ps aux | grep -v grep | grep myprocess # Use pgrep instead
ps aux | grep -v grep | grep myprocess # 建议改用 pgrep

SC2012: Use
ls
only for viewing. Use
find
for reliable output

SC2012:仅在查看内容时使用
ls
,如需可靠输出请使用
find

for file in $(ls -la) # Better: use find or globbing
for file in $(ls -la) # 更佳方案:使用 find 或通配符

SC2015: Avoid using && and || instead of if-then-else

SC2015:避免用 && 和 || 替代 if-then-else 结构

[[ -f "$file" ]] && echo "found" || echo "not found" # Less clear
[[ -f "$file" ]] && echo "found" || echo "not found" # 可读性较差

SC2016: Expressions don't expand in single quotes

SC2016:单引号中的表达式不会展开

echo '$VAR' # Literal $VAR, not variable expansion
echo '$VAR' # 输出字面量 $VAR,而非变量值

SC2026: This word is non-standard. Set POSIXLY_CORRECT

SC2026:该关键字不符合标准。若为其他Shell编写脚本,请设置 POSIXLY_CORRECT

when using with scripts for other shells

undefined
undefined

SC2100-2199: Quoting Issues

SC2100-2199:引号相关问题

bash
undefined
bash
undefined

SC2086: Double quote to prevent globbing and word splitting

SC2086:请使用双引号避免通配符与单词拆分

for i in $list; do # Should be: for i in $list or for i in "$list" echo "$i" done
for i in $list; do # 正确写法:for i in "$list" 或 for i in "${list[@]}" echo "$i" done

SC2115: Literal tilde in path not expanded. Use $HOME instead

SC2115:路径中的字面波浪号不会展开,请改用 $HOME

~/.bashrc # In strings, use "$HOME/.bashrc"
~/.bashrc # 在字符串中请使用 "$HOME/.bashrc"

SC2181: Check exit code directly with
if
, not indirectly in a list

SC2181:请直接用
if
检查退出码,而非间接通过列表判断

some_command if [ $? -eq 0 ]; then # Better: if some_command; then
some_command if [ $? -eq 0 ]; then # 更佳方案:if some_command; then

SC2206: Quote to prevent word splitting or set IFS

SC2206:请添加引号避免单词拆分,或设置 IFS

array=( $items ) # Should use: array=( $items )
undefined
array=( $items ) # 正确写法:array=( "$items" )
undefined

SC3000-3999: POSIX Compliance Issues

SC3000-3999:POSIX兼容性问题

bash
undefined
bash
undefined

SC3010: In POSIX sh, use 'case' instead of 'cond && foo'

SC3010:在POSIX sh中,请用 'case' 替代 'cond && foo' 结构

[[ $var == "value" ]] && do_something # Not POSIX
[[ $var == "value" ]] && do_something # 不符合POSIX标准

SC3043: In POSIX sh, use 'local' is undefined

SC3043:在POSIX sh中,'local' 未定义

function my_func() { local var=value # Not POSIX in some shells }
undefined
function my_func() { local var=value # 在部分Shell中不符合POSIX标准 }
undefined

Practical Configuration Examples

实用配置示例

Minimal Configuration (Strict POSIX)

最小配置(严格POSIX兼容)

bash
#!/bin/bash
bash
#!/bin/bash

Configure for maximum portability

配置以实现最大可移植性

shellcheck
--shell=sh
--external-sources
--check-sourced
script.sh
undefined
shellcheck
--shell=sh
--external-sources
--check-sourced
script.sh
undefined

Development Configuration (Bash with Relaxed Rules)

开发配置(Bash宽松规则)

bash
#!/bin/bash
bash
#!/bin/bash

Configure for Bash development

为Bash开发场景配置

shellcheck
--shell=bash
--exclude=SC1091,SC2119
--enable=all
script.sh
undefined
shellcheck
--shell=bash
--exclude=SC1091,SC2119
--enable=all
script.sh
undefined

CI/CD Integration Configuration

CI/CD集成配置

bash
#!/bin/bash
set -Eeuo pipefail
bash
#!/bin/bash
set -Eeuo pipefail

Analyze all shell scripts and fail on issues

分析所有Shell脚本,发现问题则终止流程

find . -type f -name "*.sh" | while read -r script; do echo "Checking: $script" shellcheck
--shell=bash
--format=gcc
--exclude=SC1091
"$script" || exit 1 done
undefined
find . -type f -name "*.sh" | while read -r script; do echo "检查中: $script" shellcheck
--shell=bash
--format=gcc
--exclude=SC1091
"$script" || exit 1 done
undefined

.shellcheckrc for Project

项目级 .shellcheckrc 配置

undefined
undefined

Shell dialect to analyze against

指定要分析的Shell方言

shell=bash
shell=bash

Enable optional checks

启用可选检查规则

enable=avoid-nullary-conditions,require-variable-braces,check-unassigned-uppercase
enable=avoid-nullary-conditions,require-variable-braces,check-unassigned-uppercase

Disable specific warnings

禁用特定警告

SC1091: Not following sourced files (many false positives)

SC1091:不追踪被引入的文件(存在大量误报)

disable=SC1091
disable=SC1091

SC2119: Use function_name instead of function_name -- (arguments)

SC2119:请使用 function_name 而非 function_name -- (参数)

disable=SC2119
disable=SC2119

External files to source for context

允许引入外部文件以获取上下文

external-sources=true
undefined
external-sources=true
undefined

Integration Patterns

集成模式

Pre-commit Hook Configuration

预提交钩子配置

bash
#!/bin/bash
bash
#!/bin/bash

.git/hooks/pre-commit

.git/hooks/pre-commit

#!/bin/bash set -e
#!/bin/bash set -e

Find all shell scripts changed in this commit

找出本次提交中修改的所有Shell脚本

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
undefined
git diff --cached --name-only | grep '.sh$' | while read -r script; do echo "代码检查: $script"
if ! shellcheck "$script"; then
    echo "ShellCheck 在 $script 中发现问题"
    exit 1
fi
done
undefined

GitHub Actions Workflow

GitHub Actions 工作流配置

yaml
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 {} \;
yaml
name: ShellCheck

on: [push, pull_request]

jobs:
  shellcheck:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: 运行 ShellCheck
        run: |
          sudo apt-get install shellcheck
          find . -type f -name "*.sh" -exec shellcheck {} \;

GitLab CI Pipeline

GitLab CI 流水线配置

yaml
shellcheck:
  stage: lint
  image: koalaman/shellcheck-alpine
  script:
    - find . -type f -name "*.sh" -exec shellcheck {} \;
  allow_failure: false
yaml
shellcheck:
  stage: lint
  image: koalaman/shellcheck-alpine
  script:
    - find . -type f -name "*.sh" -exec shellcheck {} \;
  allow_failure: false

Handling ShellCheck Violations

处理ShellCheck违规问题

Suppressing Specific Warnings

抑制特定警告

bash
#!/bin/bash
bash
#!/bin/bash

Disable warning for entire line

禁用整行的警告

shellcheck disable=SC2086

shellcheck disable=SC2086

for file in $(ls -la); do echo "$file" done
for file in $(ls -la); do echo "$file" done

Disable for entire script

禁用整个脚本的警告

shellcheck disable=SC1091,SC2119

shellcheck disable=SC1091,SC2119

Disable multiple warnings (format varies)

禁用多个警告(格式略有不同)

command_that_fails() { # shellcheck disable=SC2015 [ -f "$1" ] && echo "found" || echo "not found" }
command_that_fails() { # shellcheck disable=SC2015 [ -f "$1" ] && echo "found" || echo "not found" }

Disable specific check for source directive

为source指令禁用特定检查

shellcheck source=./helper.sh

shellcheck source=./helper.sh

source helper.sh
undefined
source helper.sh
undefined

Common Violations and Fixes

常见违规问题与修复方案

SC2086: Double quote to prevent word splitting

SC2086:使用双引号避免单词拆分

bash
undefined
bash
undefined

Problem

问题代码

for i in $list; do done
for i in $list; do done

Solution

修复方案

for i in $list; do done # If $list is already quoted, or for i in "${list[@]}"; do done # If list is an array
undefined
for i in "$list"; do done # 若 $list 已被引号包裹,或 for i in "${list[@]}"; do done # 若 list 是数组
undefined

SC2181: Check exit code directly

SC2181:直接检查退出码

bash
undefined
bash
undefined

Problem

问题代码

some_command if [ $? -eq 0 ]; then echo "success" fi
some_command if [ $? -eq 0 ]; then echo "成功" fi

Solution

修复方案

if some_command; then echo "success" fi
undefined
if some_command; then echo "成功" fi
undefined

SC2015: Use if-then instead of && ||

SC2015:使用if-then替代 && || 结构

bash
undefined
bash
undefined

Problem

问题代码

[ -f "$file" ] && echo "exists" || echo "not found"
[ -f "$file" ] && echo "存在" || echo "不存在"

Solution - clearer intent

修复方案 - 意图更清晰

if [ -f "$file" ]; then echo "exists" else echo "not found" fi
undefined
if [ -f "$file" ]; then echo "存在" else echo "不存在" fi
undefined

SC2016: Expressions don't expand in single quotes

SC2016:单引号中的表达式不会展开

bash
undefined
bash
undefined

Problem

问题代码

echo 'Variable value: $VAR'
echo '变量值: $VAR'

Solution

修复方案

echo "Variable value: $VAR"
undefined
echo "变量值: $VAR"
undefined

SC2009: Use pgrep instead of grep

SC2009:使用pgrep替代grep

bash
undefined
bash
undefined

Problem

问题代码

ps aux | grep -v grep | grep myprocess
ps aux | grep -v grep | grep myprocess

Solution

修复方案

pgrep -f myprocess
undefined
pgrep -f myprocess
undefined

Performance Optimization

性能优化

Checking Multiple Files

检查多个文件

bash
#!/bin/bash
bash
#!/bin/bash

Sequential checking

串行检查

for script in *.sh; do shellcheck "$script" done
for script in *.sh; do shellcheck "$script" done

Parallel checking (faster)

并行检查(速度更快)

find . -name "*.sh" -print0 |
xargs -0 -P 4 -n 1 shellcheck
undefined
find . -name "*.sh" -print0 |
xargs -0 -P 4 -n 1 shellcheck
undefined

Caching Results

缓存检查结果

bash
#!/bin/bash

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
bash
#!/bin/bash

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

Output Formats

输出格式

Default Format

默认格式

bash
shellcheck script.sh
bash
shellcheck script.sh

Output:

输出示例:

script.sh:1:3: warning: foo is referenced but not assigned. [SC2154]

script.sh:1:3: warning: foo is referenced but not assigned. [SC2154]

undefined
undefined

GCC Format (for CI/CD)

GCC格式(适用于CI/CD)

bash
shellcheck --format=gcc script.sh
bash
shellcheck --format=gcc script.sh

Output:

输出示例:

script.sh:1:3: warning: foo is referenced but not assigned.

script.sh:1:3: warning: foo is referenced but not assigned.

undefined
undefined

JSON Format (for parsing)

JSON格式(适用于解析)

bash
shellcheck --format=json script.sh
bash
shellcheck --format=json script.sh

Output:

输出示例:

[{"file": "script.sh", "line": 1, "column": 3, "level": "warning", "code": 2154, "message": "..."}]

[{"file": "script.sh", "line": 1, "column": 3, "level": "warning", "code": 2154, "message": "..."}]

undefined
undefined

Quiet Format

静默格式

bash
shellcheck --format=quiet script.sh
bash
shellcheck --format=quiet script.sh

Returns non-zero if issues found, no output otherwise

发现问题时返回非零值,无其他输出

undefined
undefined

Best Practices

最佳实践

  1. Run ShellCheck in CI/CD - Catch issues before merging
  2. Configure for your target shell - Don't analyze bash as sh
  3. Document exclusions - Explain why violations are suppressed
  4. Address violations - Don't just disable warnings
  5. Enable strict mode - Use
    --enable=all
    with careful exclusions
  6. Update regularly - Keep ShellCheck current for new checks
  7. Use pre-commit hooks - Catch issues locally before pushing
  8. Integrate with editors - Get real-time feedback during development
  1. 在CI/CD中运行ShellCheck - 在代码合并前发现问题
  2. 针对目标Shell配置 - 不要将Bash脚本按sh分析
  3. 记录规则排除原因 - 说明为何要抑制某些违规警告
  4. 解决违规问题 - 不要仅禁用警告
  5. 启用严格模式 - 谨慎排除规则的同时使用
    --enable=all
  6. 定期更新ShellCheck - 保持工具版本以获取新的检查规则
  7. 使用预提交钩子 - 在本地推送代码前发现问题
  8. 与编辑器集成 - 在开发过程中获取实时反馈

Resources

参考资源