shellcheck-cicd-2025

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

🚨 CRITICAL GUIDELINES

⚠️ 关键指南

Windows File Path Requirements

Windows文件路径要求

MANDATORY: Always Use Backslashes on Windows for File Paths
When using Edit or Write tools on Windows, you MUST use backslashes (
\
) in file paths, NOT forward slashes (
/
).
Examples:
  • ❌ WRONG:
    D:/repos/project/file.tsx
  • ✅ CORRECT:
    D:\repos\project\file.tsx
This applies to:
  • Edit tool file_path parameter
  • Write tool file_path parameter
  • All file operations on Windows systems
强制要求:在Windows系统中始终使用反斜杠(\)表示文件路径
在Windows系统中使用编辑或写入工具时,必须使用反斜杠(
\
)表示文件路径,而非正斜杠(
/
)。
示例:
  • ❌ 错误:
    D:/repos/project/file.tsx
  • ✅ 正确:
    D:\repos\project\file.tsx
此要求适用于:
  • 编辑工具的file_path参数
  • 写入工具的file_path参数
  • Windows系统上的所有文件操作

Documentation Guidelines

文档指南

NEVER create new documentation files unless explicitly requested by the user.
  • Priority: Update existing README.md files rather than creating new documentation
  • Repository cleanliness: Keep repository root clean - only README.md unless user requests otherwise
  • Style: Documentation should be concise, direct, and professional - avoid AI-generated tone
  • User preference: Only create additional .md files when user specifically asks for documentation

除非用户明确要求,否则绝不创建新的文档文件。
  • 优先级:优先更新现有README.md文件,而非创建新文档
  • 仓库整洁性:保持仓库根目录整洁 - 除非用户要求,否则仅保留README.md
  • 风格:文档应简洁、直接、专业 - 避免AI生成的语气
  • 用户偏好:仅在用户明确要求文档时才创建额外的.md文件

ShellCheck CI/CD Integration (2025)

ShellCheck CI/CD集成(2025版)

ShellCheck: Non-Negotiable in 2025

ShellCheck:2025年不可或缺的工具

ShellCheck is now considered mandatory in modern bash workflows (2025 best practices):
在2025年的现代Bash工作流中,ShellCheck已被视为强制使用的工具:

Latest Version: v0.11.0 (August 2025)

最新版本:v0.11.0(2025年8月)

What's New:
  • Full Bash 5.3 support (
    ${| cmd; }
    and
    source -p
    )
  • New warnings: SC2327/SC2328 (capture group issues)
  • POSIX.1-2024 compliance: SC3013 removed (-ot/-nt/-ef now POSIX standard)
  • Enhanced static analysis capabilities
  • Improved performance and accuracy
新增特性:
  • 全面支持Bash 5.3(包括
    ${| cmd; }
    source -p
    语法)
  • 新增警告:SC2327/SC2328(捕获组问题)
  • 符合POSIX.1-2024标准:移除SC3013规则(
    -ot/-nt/-ef
    现已成为POSIX标准语法)
  • 增强的静态分析能力
  • 提升的性能与准确性

Why Mandatory?

为何是强制要求?

  • Catches subtle bugs before production
  • Prevents common security vulnerabilities
  • Enforces consistent code quality
  • Required by most DevOps teams
  • Standard in enterprise environments
  • Supports latest POSIX.1-2024 standard
  • 在上线前发现潜在的细微bug
  • 预防常见的安全漏洞
  • 保证代码质量的一致性
  • 大多数DevOps团队的必备要求
  • 企业环境中的标准配置
  • 支持最新的POSIX.1-2024标准

Installation

安装方法

bash
undefined
bash
undefined

Ubuntu/Debian

Ubuntu/Debian

apt-get install shellcheck
apt-get install shellcheck

macOS

macOS

brew install shellcheck
brew install shellcheck

Alpine (Docker)

Alpine (Docker)

apk add shellcheck
apk add shellcheck

Windows (WSL/Git Bash)

Windows (WSL/Git Bash)

choco install shellcheck
choco install shellcheck

Or download binary

或下载二进制文件

wget https://github.com/koalaman/shellcheck/releases/latest/download/shellcheck-stable.linux.x86_64.tar.xz tar -xf shellcheck-stable.linux.x86_64.tar.xz sudo cp shellcheck-stable/shellcheck /usr/local/bin/
undefined
wget https://github.com/koalaman/shellcheck/releases/latest/download/shellcheck-stable.linux.x86_64.tar.xz tar -xf shellcheck-stable.linux.x86_64.tar.xz sudo cp shellcheck-stable/shellcheck /usr/local/bin/
undefined

GitHub Actions Integration

GitHub Actions集成

Mandatory Pre-Merge Check

强制预合并检查

yaml
undefined
yaml
undefined

.github/workflows/shellcheck.yml

.github/workflows/shellcheck.yml

name: ShellCheck
on: pull_request: paths: - '**.sh' - '**Dockerfile' push: branches: [main]
jobs: shellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Run ShellCheck
  uses: ludeeus/action-shellcheck@master
  with:
    severity: warning
    format: gcc  # or: tty, json, checkstyle
    scandir: './scripts'
    # Fail on any issues
    ignore_paths: 'node_modules'

# Block merge on failures
- name: Annotate PR
  if: failure()
  uses: actions/github-script@v6
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '⛔ ShellCheck validation failed. Fix issues before merging.'
      })
undefined
name: ShellCheck
on: pull_request: paths: - '**.sh' - '**Dockerfile' push: branches: [main]
jobs: shellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: 运行ShellCheck
  uses: ludeeus/action-shellcheck@master
  with:
    severity: warning
    format: gcc  # 或:tty, json, checkstyle
    scandir: './scripts'
    # 存在任何问题则失败
    ignore_paths: 'node_modules'

# 失败时阻止合并
- name: 为PR添加注释
  if: failure()
  uses: actions/github-script@v6
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '⛔ ShellCheck验证未通过。请修复问题后再合并。'
      })
undefined

Azure DevOps Integration

Azure DevOps集成

yaml
undefined
yaml
undefined

azure-pipelines.yml

azure-pipelines.yml

trigger:
  • main
pr:
  • main
stages:
  • stage: Validate jobs:
    • job: ShellCheck pool: vmImage: 'ubuntu-24.04'
      steps:
      • script: | sudo apt-get install -y shellcheck displayName: 'Install ShellCheck'
      • script: | find . -name "*.sh" -type f | xargs shellcheck --format=gcc --severity=warning displayName: 'Run ShellCheck' failOnStderr: true
      • task: PublishTestResults@2 condition: always() inputs: testResultsFormat: 'JUnit' testResultsFiles: '**/shellcheck-results.xml' failTaskOnFailedTests: true
undefined
trigger:
  • main
pr:
  • main
stages:
  • stage: 验证 jobs:
    • job: ShellCheck pool: vmImage: 'ubuntu-24.04'
      steps:
      • script: | sudo apt-get install -y shellcheck displayName: '安装ShellCheck'
      • script: | find . -name "*.sh" -type f | xargs shellcheck --format=gcc --severity=warning displayName: '运行ShellCheck' failOnStderr: true
      • task: PublishTestResults@2 condition: always() inputs: testResultsFormat: 'JUnit' testResultsFiles: '**/shellcheck-results.xml' failTaskOnFailedTests: true
undefined

Git Hooks (Pre-Commit)

Git钩子(预提交)

bash
undefined
bash
undefined

.git/hooks/pre-commit

.git/hooks/pre-commit

#!/usr/bin/env bash set -o errexit set -o nounset set -o pipefail
#!/usr/bin/env bash set -o errexit set -o nounset set -o pipefail

Find all staged .sh files

查找所有已暂存的.sh文件

mapfile -t STAGED_SH < <(git diff --cached --name-only --diff-filter=ACMR | grep '.sh$' || true)
if [ ${#STAGED_SH[@]} -eq 0 ]; then exit 0 fi
echo "Running ShellCheck on staged files..."
mapfile -t STAGED_SH < <(git diff --cached --name-only --diff-filter=ACMR | grep '.sh$' || true)
if [ ${#STAGED_SH[@]} -eq 0 ]; then exit 0 fi
echo "正在对已暂存文件运行ShellCheck..."

Run ShellCheck

运行ShellCheck

shellcheck --format=gcc --severity=warning "${STAGED_SH[@]}"
if [ $? -ne 0 ]; then echo "⛔ ShellCheck failed. Fix issues before committing." exit 1 fi
echo "✅ ShellCheck passed" exit 0

**Install Pre-Commit Hook:**
```bash
chmod +x .git/hooks/pre-commit
shellcheck --format=gcc --severity=warning "${STAGED_SH[@]}"
if [ $? -ne 0 ]; then echo "⛔ ShellCheck未通过。请修复问题后再提交。" exit 1 fi
echo "✅ ShellCheck通过" exit 0

**安装预提交钩子:**
```bash
chmod +x .git/hooks/pre-commit

Or use pre-commit framework

或使用pre-commit框架

.pre-commit-config.yaml

.pre-commit-config.yaml

repos:
repos:

Install

安装

pip install pre-commit pre-commit install
undefined
pip install pre-commit pre-commit install
undefined

VS Code Integration

VS Code集成

json
// .vscode/settings.json
{
  "shellcheck.enable": true,
  "shellcheck.run": "onType",
  "shellcheck.executablePath": "/usr/local/bin/shellcheck",
  "shellcheck.exclude": ["SC1090", "SC1091"],  // Optional excludes
  "shellcheck.customArgs": [
    "-x",  // Follow source files
    "--severity=warning"
  ]
}
json
// .vscode/settings.json
{
  "shellcheck.enable": true,
  "shellcheck.run": "onType",
  "shellcheck.executablePath": "/usr/local/bin/shellcheck",
  "shellcheck.exclude": ["SC1090", "SC1091"],  // 可选排除的规则
  "shellcheck.customArgs": [
    "-x",  // 跟随源文件
    "--severity=warning"
  ]
}

Docker Build Integration

Docker构建集成

dockerfile
undefined
dockerfile
undefined

Dockerfile with ShellCheck validation

包含ShellCheck验证的Dockerfile

FROM alpine:3.19 AS builder
FROM alpine:3.19 AS builder

Install ShellCheck

安装ShellCheck

RUN apk add --no-cache shellcheck bash
RUN apk add --no-cache shellcheck bash

Copy scripts

复制脚本

COPY scripts/ /scripts/
COPY scripts/ /scripts/

Validate all scripts before continuing

在继续构建前验证所有脚本

RUN find /scripts -name "*.sh" -type f -exec shellcheck --severity=warning {} +
RUN find /scripts -name "*.sh" -type f -exec shellcheck --severity=warning {} +

Final stage

最终阶段

FROM alpine:3.19 COPY --from=builder /scripts/ /scripts/ RUN chmod +x /scripts/*.sh
ENTRYPOINT ["/scripts/entrypoint.sh"]
undefined
FROM alpine:3.19 COPY --from=builder /scripts/ /scripts/ RUN chmod +x /scripts/*.sh
ENTRYPOINT ["/scripts/entrypoint.sh"]
undefined

Common ShellCheck Rules (2025)

常用ShellCheck规则(2025版)

New in v0.11.0: SC2327/SC2328 - Capture Groups

v0.11.0新增:SC2327/SC2328 - 捕获组问题

bash
undefined
bash
undefined

❌ Bad - Capture groups may not work as expected

❌ 错误示例 - 捕获组可能无法按预期工作

if [[ "$string" =~ ([0-9]+).([0-9]+) ]]; then echo "$1" # Wrong: $1 is script arg, not capture group fi
if [[ "$string" =~ ([0-9]+).([0-9]+) ]]; then echo "$1" # 错误:$1是脚本参数,而非捕获组 fi

✅ Good - Use BASH_REMATCH array

✅ 正确示例 - 使用BASH_REMATCH数组

if [[ "$string" =~ ([0-9]+).([0-9]+) ]]; then echo "${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" fi
undefined
if [[ "$string" =~ ([0-9]+).([0-9]+) ]]; then echo "${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" fi
undefined

SC2294: eval Negates Array Benefits (New)

SC2294:eval会抵消数组的安全性(新增规则)

bash
undefined
bash
undefined

❌ Bad - eval defeats array safety

❌ 错误示例 - eval会破坏数组的安全性

eval "command ${array[@]}"
eval "command ${array[@]}"

✅ Good - Direct array usage

✅ 正确示例 - 直接使用数组

command "${array[@]}"
undefined
command "${array[@]}"
undefined

SC2295: Quote Expansions Inside ${}

SC2295:在${}内为扩展内容添加引号

bash
undefined
bash
undefined

❌ Bad

❌ 错误示例

echo "${var-$default}" # $default not quoted
echo "${var-$default}" # $default未添加引号

✅ Good

✅ 正确示例

echo "${var-"$default"}"
undefined
echo "${var-"$default"}"
undefined

SC2086: Quote Variables

SC2086:为变量添加引号

bash
undefined
bash
undefined

❌ Bad

❌ 错误示例

file=$1 cat $file # Fails if filename has spaces
file=$1 cat $file # 如果文件名包含空格会失败

✅ Good

✅ 正确示例

file=$1 cat "$file"
undefined
file=$1 cat "$file"
undefined

SC2046: Quote Command Substitution

SC2046:为命令替换添加引号

bash
undefined
bash
undefined

❌ Bad

❌ 错误示例

for file in $(find . -name "*.txt"); do echo $file done
for file in $(find . -name "*.txt"); do echo $file done

✅ Good

✅ 正确示例

find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do echo "$file" done
undefined
find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do echo "$file" done
undefined

SC2155: Separate Declaration and Assignment

SC2155:变量声明与赋值分离

bash
undefined
bash
undefined

❌ Bad

❌ 错误示例

local result=$(command) # Hides command exit code
local result=$(command) # 会隐藏命令的退出码

✅ Good

✅ 正确示例

local result result=$(command)
undefined
local result result=$(command)
undefined

SC2164: Use cd || exit

SC2164:使用cd || exit

bash
undefined
bash
undefined

❌ Bad

❌ 错误示例

cd /some/directory ./script.sh # Runs in wrong dir if cd fails
cd /some/directory ./script.sh # 如果cd失败,会在错误的目录运行脚本

✅ Good

✅ 正确示例

cd /some/directory || exit 1 ./script.sh
undefined
cd /some/directory || exit 1 ./script.sh
undefined

Google Shell Style Guide (50-Line Limit)

Google Shell风格指南(50行限制)

2025 recommendation: Keep scripts under 50 lines:
bash
undefined
2025年建议:脚本长度控制在50行以内
bash
undefined

❌ Bad: 500-line monolithic script

❌ 错误示例:500行的单体脚本

#!/usr/bin/env bash
#!/usr/bin/env bash

... 500 lines of code ...

... 500行代码 ...

✅ Good: Modular scripts < 50 lines each

✅ 正确示例:模块化脚本,每个脚本不超过50行

lib/logging.sh (20 lines)

lib/logging.sh(20行)

log_info() { echo "[INFO] $"; } log_error() { echo "[ERROR] $" >&2; }
log_info() { echo "[INFO] $"; } log_error() { echo "[ERROR] $" >&2; }

lib/validation.sh (30 lines)

lib/validation.sh(30行)

validate_input() { ... } check_dependencies() { ... }
validate_input() { ... } check_dependencies() { ... }

main.sh (40 lines)

main.sh(40行)

source "$(dirname "$0")/lib/logging.sh" source "$(dirname "$0")/lib/validation.sh"
main() { validate_input "$@" check_dependencies

... core logic ...

}
main "$@"
undefined
source "$(dirname "$0")/lib/logging.sh" source "$(dirname "$0")/lib/validation.sh"
main() { validate_input "$@" check_dependencies

... 核心逻辑 ...

}
main "$@"
undefined

Enforce in CI/CD

在CI/CD中强制执行

Fail Build on Issues

存在问题则构建失败

yaml
undefined
yaml
undefined

Strict enforcement

严格强制执行

  • name: ShellCheck (Strict) run: | shellcheck --severity=warning scripts/*.sh

    Exit code 1 fails the build

  • run: | shellcheck --severity=warning scripts/*.sh

    退出码1会导致构建失败

Advisory only (warnings but don't fail)

仅作为建议(仅警告但不终止构建)

  • name: ShellCheck (Advisory) run: | shellcheck --severity=warning scripts/*.sh || true

    Logs warnings but doesn't fail

undefined
  • run: | shellcheck --severity=warning scripts/*.sh || true

    记录警告但不终止构建

undefined

Generate Reports

生成报告

bash
undefined
bash
undefined

JSON format for parsing

用于解析的JSON格式

shellcheck --format=json scripts/*.sh > shellcheck-report.json
shellcheck --format=json scripts/*.sh > shellcheck-report.json

GitHub annotations format

GitHub注释格式

shellcheck --format=gcc scripts/*.sh
shellcheck --format=gcc scripts/*.sh

Human-readable

人类可读格式

shellcheck --format=tty scripts/*.sh
undefined
shellcheck --format=tty scripts/*.sh
undefined

Modern Error Handling Trio (2025)

现代错误处理三件套(2025版)

Always use with ShellCheck validation:
bash
#!/usr/bin/env bash
请始终与ShellCheck验证配合使用
bash
#!/usr/bin/env bash

Modern error handling (non-negotiable in 2025)

现代错误处理(2025年强制要求)

set -o errexit # Exit on command failure set -o nounset # Exit on undefined variable set -o pipefail # Exit on pipe failure
set -o errexit # 命令失败时退出 set -o nounset # 遇到未定义变量时退出 set -o pipefail # 管道失败时退出

ShellCheck approved

ShellCheck认可的写法

main() { local config_file="${1:?Config file required}"
if [[ ! -f "$config_file" ]]; then echo "Error: Config file not found: $config_file" >&2 return 1 fi

Safe command execution

local result result=$(process_config "$config_file")
echo "$result" }
main "$@"
undefined
main() { local config_file="${1:?必须提供配置文件}"
if [[ ! -f "$config_file" ]]; then echo "错误:未找到配置文件:$config_file" >&2 return 1 fi

安全执行命令

local result result=$(process_config "$config_file")
echo "$result" }
main "$@"
undefined

Best Practices (2025)

最佳实践(2025版)

  1. Run ShellCheck in CI/CD (mandatory)
  2. Use pre-commit hooks to catch issues early
  3. Keep scripts under 50 lines (Google Style Guide)
  4. Use modern error handling trio (errexit, nounset, pipefail)
  5. Fix all warnings before merging
  6. Document any disabled rules with reasoning
  7. Integrate with IDE for real-time feedback
  1. 在CI/CD中运行ShellCheck(强制要求)
  2. 使用预提交钩子提前发现问题
  3. 将脚本长度控制在50行以内(Google风格指南)
  4. 使用现代错误处理三件套(errexit、nounset、pipefail)
  5. 合并前修复所有警告
  6. 对禁用的规则添加文档说明及原因
  7. 与IDE集成获取实时反馈

Resources

参考资源