mcpField
B
bash-pro

bash-pro

github.com/sickn33开发48.7k967 次安装今天更新
代码仓库

关于 bash-pro

bash-pro 是用于编写和审查 Bash 自动化、CI/CD 与运维脚本的技能,侧重防御式错误处理、安全输入处理、可移植性以及使用 Bats 和 ShellCheck 测试。

主要功能

  1. 01严格错误处理与陷阱清理
  2. 02安全解析参数和校验输入
  3. 03可移植的文件与进程操作
  4. 04使用 Bats 测试和 ShellCheck 检查
  5. 05日志与脚本文档规范

适用场景

  1. 01审查脚本中的不安全写法
  2. 02构建 CI/CD Bash 自动化
  3. 03加固会修改文件的脚本
  4. 04在目标平台间测试脚本

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill bash-pro

安装后在 Claude Code 中输入/bash-pro确认已加载。

详细介绍

适用场景

  • 编写或审查用于自动化、CI/CD 或运维的 Bash 脚本
  • 加固 Shell 脚本,以提升安全性和可移植性

不适用场景

  • 需要仅使用 POSIX Shell,不能使用 Bash 特性
  • 任务需要使用更高级的语言来处理复杂逻辑
  • 需要使用 Windows 原生脚本(PowerShell)

指南

  1. 定义脚本的输入、输出和失败模式。
  2. 启用严格模式,并安全地解析参数。
  3. 使用防御性模式实现核心逻辑。
  4. 使用 Bats 和 ShellCheck 添加测试和 lint 检查。

安全性

  • 将输入视为不可信内容;避免使用 eval 和不安全的通配符。
  • 执行破坏性操作前,优先使用试运行模式。

重点领域

  • 采用严格错误处理进行防御式编程
  • 符合 POSIX 标准并支持跨平台移植
  • 安全地解析参数并验证输入
  • 可靠地处理文件操作和临时资源
  • 保障进程编排和管道安全
  • 提供适用于生产环境的日志记录和错误报告
  • 使用 Bats 框架进行全面测试
  • 使用 ShellCheck 进行静态分析,并使用 shfmt 格式化代码
  • 遵循现代 Bash 5.x 特性和最佳实践
  • 集成 CI/CD 和自动化工作流

方法

  • 始终使用严格模式 set -Eeuo pipefail,并正确设置错误捕获
  • 为所有变量展开加上引号,避免单词拆分和通配符匹配问题
  • 优先使用数组和恰当的迭代方式,避免使用 for f in $(ls) 等不安全模式
  • Bash 条件判断使用 [[ ]];需要符合 POSIX 标准时改用 [ ]
  • 使用 getopts 和 usage 函数全面解析参数
  • 使用 mktemp 安全地创建临时文件和目录,并通过清理陷阱进行清理
  • 优先使用 printf 而非 echo,以确保输出格式可预测
  • 使用命令替换 $(),而非反引号,以提高可读性
  • 使用时间戳和可配置的详细程度实现结构化日志记录
  • 设计幂等脚本,并支持试运行模式
  • 使用 shopt -s inherit_errexit,以便在 Bash 4.4+ 中更好地传播错误
  • 使用 IFS=$'\n\t',避免空格导致意外的单词拆分
  • 使用 : "${VAR:?message}" 验证必需的环境变量
  • 使用 -- 结束选项解析,并使用 rm -rf -- "$dir" 执行安全操作
  • 仅允许在已脱敏的非机密路径中使用 set -x;跟踪模式会展开凭据和参数
  • 使用 xargs -0 和 NUL 分隔符安全地编排子进程
  • 使用 readarray/mapfile 安全地将命令输出填充到数组中
  • 使用可靠方式检测脚本目录:SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
  • 使用 NUL 安全模式:find -print0 | while IFS= read -r -d '' file; do ...; done

兼容性与可移植性

  • 使用 #!/usr/bin/env bash 作为 shebang,以便在不同系统间移植
  • 在脚本启动时检查 Bash 版本:对于 Bash 4.4+ 特性,使用 (( BASH_VERSINFO[0] > 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 4) ))
  • 验证所需的外部命令是否存在:command -v jq &>/dev/null || exit 1
  • 检测平台差异:case "$(uname -s)" in Linux*) ... ;; Darwin*) ... ;; esac
  • 处理 GNU 与 BSD 工具的差异(例如,sed -i 与 sed -i '')
  • 在所有目标平台(Linux、macOS、BSD 变体)上测试脚本
  • 在脚本头部注释中说明最低版本要求
  • 为平台特有功能提供回退实现
  • 为提升可移植性,尽可能优先使用 Bash 内置功能,而非外部命令
  • 需要符合 POSIX 标准时,避免使用 Bash 特有语法;若使用 Bash 特有功能,则应说明

可读性与可维护性

  • 在脚本中使用完整形式的选项,提升清晰度:使用 --verbose 而不是 -v
  • 使用一致的命名方式:函数和变量使用 snake_case,常量使用 UPPER_CASE
  • 添加注释块形式的分节标题,整理相关函数
  • 函数长度控制在 50 行以内;将较大的函数重构为更小的组件
  • 将相关函数归组,并添加描述性分节标题
  • 使用能说明用途的描述性函数名:使用 validate_input_file,而不是 check_file
  • 为不明显的逻辑添加行内注释,避免赘述显而易见的内容
  • 保持缩进一致(使用 2 个或 4 个空格,绝不混用制表符和空格)
  • 为保持一致,将左花括号放在同一行:function_name() {
  • 在函数内使用空行分隔逻辑区块
  • 在头部注释中说明函数参数和返回值
  • 将魔法数字和字符串提取为脚本顶部的命名常量

安全模式

  • 使用 readonly 声明常量,避免意外修改
  • 所有函数变量都使用 local 关键字,避免污染全局作用域
  • 为外部命令设置 timeout:curl --connect-timeout 5 --max-time 30 ... 可限制网络调用时长;macOS 不自带 GNU timeout
  • 操作前验证文件权限:[[ -r "$file" ]] || exit 1
  • 进程替换可能会隐藏生产者的失败状态,使其无法被 pipefail 检测到;对于关键输入,应显式等待并检查其状态
  • 在命令或文件操作中使用用户输入前,先对其进行清理
  • 使用模式匹配验证数字输入:[[ $num =~ ^[0-9]+$ ]]
  • 绝不对用户输入使用 eval;使用数组动态构造命令
  • 对敏感操作设置严格的 umask:(umask 077; touch "$secure_file")
  • 记录与安全相关的操作(身份验证、权限变更、文件访问)
  • 使用 -- 分隔选项和参数:rm -rf -- "$user_input"
  • 使用环境变量前先验证:: "${REQUIRED_VAR:?not set}"
  • 显式检查所有安全关键操作的退出码
  • 使用 trap 确保即使异常退出也能完成清理

性能优化

  • 避免在循环中创建子 shell;使用 while read,而不是 for i in $(cat file)
  • 优先使用 Bash 内置功能,而非外部命令:使用 [[ ]] 而不是 test,使用 ${var//pattern/replacement} 而不是 sed
  • 批量执行操作,而不是重复执行单个操作(例如,用一个 sed 搭配多个表达式)
  • 使用 mapfile/readarray 高效地从命令输出填充数组
  • 避免重复进行命令替换;将结果存入变量后重复使用
  • 使用算术展开 $(( )) 进行计算,而不是 expr
  • 格式化输出时优先使用 printf,而不是 echo(速度更快且更可靠)
  • 使用关联数组进行查找,而不是反复使用 grep
  • 对大型文件逐行处理,而不是将整个文件载入内存
  • 对彼此独立的操作,使用 xargs -P 并行处理

文档规范

  • 实现 --help 和 -h 标志,显示用法、选项和示例
  • 提供 --version 标志,显示脚本版本和版权信息
  • 在帮助输出中提供常见用例的使用示例
  • 说明所有命令行选项的用途
  • 在用法说明中明确列出必需参数和可选参数
  • 说明退出码:成功时为 0,一般错误时为 1,特定失败使用对应的专用代码
  • 添加先决条件章节,列出必需的命令及其版本
  • 添加头部注释块,说明脚本用途、作者和修改日期
  • 说明脚本使用或要求的环境变量
  • 在帮助中提供常见问题的故障排查章节
  • 使用 shdoc 根据特殊注释格式生成文档
  • 使用 shellman 创建 man 手册页,以便集成到系统中
  • 对于复杂脚本,使用 Mermaid 或 GraphViz 绘制架构图

Bash 现代特性(5.x)

  • 对照目标 Bash 手册逐项确认所需特性,不要假设所有 Bash 5.x 版本的转换、shopt 选项和重定向行为都相同。
  • EPOCHREALTIME 以微秒精度报告纪元秒数;它是挂钟时间,不是单调基准计时器。
  • 使用现代特性前先检查版本:(( BASH_VERSINFO[0] > 5 || (BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 2) ))
  • 使用 ${parameter@Q} 输出经过 shell 引用的内容(Bash 4.4+)
  • 使用 ${parameter@E} 展开转义序列(Bash 4.4+)
  • 使用 ${parameter@P} 展开提示符(Bash 4.4+)
  • 使用 ${parameter@A} 获取赋值格式(Bash 4.4+)
  • 使用 wait -n 等待任意后台作业(Bash 4.3+)
  • 使用 mapfile -d delim 指定自定义分隔符(Bash 4.4+)

CI/CD 集成

  • GitHub Actions:使用 shellcheck-problem-matchers 添加内联注释
  • Pre-commit 钩子:在 .pre-commit-config.yaml 中配置 shellcheck、shfmt、checkbashisms
  • 矩阵测试:在 Linux 和 macOS 上使用 Bash 4.4、5.0、5.1、5.2 进行测试
  • 容器测试:使用官方 bash:5.2 Docker 镜像进行可复现的测试
  • CodeQL:在适用的情况下使用受支持语言的分析;它不是通用的 Bash 分析器
  • Actionlint:验证使用 shell 脚本的 GitHub Actions 工作流文件
  • 自动发布:自动标记版本并生成变更日志
  • 覆盖率报告:跟踪测试覆盖率,并在出现回归时使构建失败
  • 示例工作流:shellcheck *.sh && shfmt -d *.sh && bats test/

安全扫描与加固

  • SAST:集成 Semgrep,并为 shell 特有漏洞编写自定义规则
  • 密钥检测:使用 gitleaks 或 trufflehog,防止凭据泄露
  • 供应链:验证所引入外部脚本的校验和
  • 沙箱:先将不可信脚本作为数据检查;仅使用容器并不意味着获准执行脚本,也不能隔离网络、挂载或密钥
  • SBOM:记录依赖项和外部工具,以满足合规要求
  • 安全 lint:启用面向安全的规则,使用 ShellCheck 检查代码
  • 权限分析:审计脚本,检查是否不必要地要求 root/sudo 权限
  • 输入清理:根据允许列表验证所有外部输入
  • 审计日志:将所有与安全相关的操作记录到 syslog
  • 容器安全:扫描脚本执行环境中的漏洞

可观测性与日志记录

  • 结构化日志:输出 JSON,供日志聚合系统使用
  • 日志级别:实现可配置详细程度的 DEBUG、INFO、WARN、ERROR
  • Syslog 集成:使用 logger 命令将日志集成到系统日志中
  • 分布式追踪:添加追踪 ID,以关联多脚本工作流
  • 指标导出:输出 Prometheus 格式的指标以供监控
  • 错误上下文:包含已脱敏的位置和状态信息;绝不输出环境变量或展开后的机密命令
  • 日志轮转:为长时间运行的脚本配置日志文件轮转
  • 性能指标:跟踪执行时间、资源用量和外部调用延迟
  • 示例:log_info() { logger -t "$SCRIPT_NAME" -p user.info "$*"; echo "[INFO] $*" >&2; }

质量检查清单

  • 脚本通过 ShellCheck 静态分析,且抑制项尽可能少
  • 使用 shfmt 和标准选项统一格式化代码
  • 使用 Bats 全面覆盖测试,包括边界情况
  • 所有变量展开都正确加引号
  • 错误处理涵盖所有失败模式,并提供有意义的消息
  • 使用 EXIT 陷阱正确清理临时资源
  • 脚本支持 --help,并提供清晰的用法说明
  • 输入验证可防止注入攻击,并处理边界情况
  • 脚本可在目标平台(Linux、macOS)上移植运行
  • 性能满足预期工作负载和数据规模的要求

输出

  • 可用于生产环境的 Bash 脚本,并采用防御式编程实践
  • 使用 bats-core 或 shellspec 编写的全面测试套件,并输出 TAP 格式结果
  • 用于自动化测试的 CI/CD 流水线配置(GitHub Actions、GitLab CI)
  • 使用 shdoc 生成的文档,以及使用 shellman 生成的 man 页面
  • 结构化的项目布局,包含可复用的库函数和依赖管理
  • 静态分析配置文件(.shellcheckrc、.shfmt.toml、.editorconfig)
  • 针对关键工作流的性能基准测试和性能分析报告
  • 安全审查,包含 SAST、密钥扫描和漏洞报告
  • 调试工具,包含跟踪模式、结构化日志记录和可观测性
  • Bash 3→5 升级和旧版现代化迁移指南
  • 软件包分发配置(Homebrew 配方、deb/rpm 规格)
  • 用于可复现执行环境的容器镜像

必备工具

静态分析与格式化
  • ShellCheck:静态分析器,配置中启用 enable=all 和 external-sources=true
  • shfmt:Shell 脚本格式化工具,采用标准配置(-i 2 -ci -bn -sr -kp)
  • checkbashisms:检测 Bash 专属结构,以分析可移植性
  • Semgrep:SAST 工具,包含针对 Shell 专属安全问题的自定义规则
  • CodeQL:分析受支持的语言和 Actions;对于独立 Bash,使用 ShellCheck
测试框架
  • bats-core:Bats 的维护分支,具备现代功能并积极开发
  • shellspec:BDD 风格测试框架,提供丰富的断言和模拟功能
  • shunit2:用于 Shell 脚本的 xUnit 风格测试框架
  • bashing:支持模拟和测试隔离的测试框架
现代开发工具
  • bashly:用于构建命令行应用的 CLI 框架生成器
  • basher:用于依赖管理的 Bash 包管理器
  • bpkg:采用类似 npm 的接口的 Bash 包管理器替代方案
  • shdoc:根据 Shell 脚本注释生成 Markdown 文档
  • shellman:根据 Shell 脚本生成 man 页面
CI/CD 与自动化
  • pre-commit:多语言 pre-commit 钩子框架
  • actionlint:GitHub Actions 工作流检查工具
  • gitleaks:密钥扫描工具,用于防止凭据泄露
  • Makefile:用于 lint、格式化、测试和发布工作流的自动化工具

应避免的常见陷阱

  • for f in $(ls ...) 会导致单词拆分和通配符匹配错误(请改用 find -print0 | while IFS= read -r -d '' f; do ...; done)
  • 未给变量展开加引号,导致意外行为
  • 在复杂流程中依赖 set -e,却没有适当的错误捕获
  • 使用 echo 输出数据(为确保可靠性,优先使用 printf)
  • 未为临时文件和目录设置清理陷阱
  • 不安全地填充数组(请使用 readarray/mapfile,而不是命令替换)
  • 忽视二进制安全的文件处理(处理文件名时务必考虑使用 NUL 分隔符)

依赖管理

  • 包管理器:使用 basher 或 bpkg 安装 Shell 脚本依赖
  • 供应商化:将依赖复制到项目中,以实现可复现构建
  • 锁定文件:记录所用依赖的确切版本
  • 校验和验证:验证引入的外部脚本的完整性
  • 版本固定:将依赖锁定到特定版本,以避免破坏性变更
  • 依赖隔离:为不同的依赖集合使用单独的目录
  • 更新自动化:使用 Dependabot 或 Renovate 自动更新依赖
  • 安全扫描:扫描依赖中已知的漏洞
  • 示例:basher install username/repo@version 或 bpkg install username/repo -g

高级技巧

  • 错误上下文:使用 trap 'echo "Error at line $LINENO: exit $?" >&2' ERR 进行调试
  • 安全处理临时文件:tmpdir=$(mktemp -d) || exit 1; trap 'rm -rf -- "$tmpdir"' EXIT
  • 版本检查:使用现代功能前,先运行 (( BASH_VERSINFO[0] >= 5 ))
  • 二进制安全数组:readarray -d '' files < <(find . -print0)
  • 函数返回值:使用 declare -g result 从函数返回复杂数据
  • 关联数组:使用 declare -A config=([host]="localhost" [port]="8080") 表示复杂数据结构
  • 参数展开:${filename%.sh} 移除扩展名,${path##*/} 获取基本文件名,${text//old/new} 替换所有匹配项
  • 信号处理:使用 trap cleanup_function SIGHUP SIGINT SIGTERM 实现平稳关闭
  • 命令分组:{ cmd1; cmd2; } > output.log 共享重定向,( cd dir && cmd ) 使用子 Shell 实现隔离
  • 协程:coproc proc { cmd; }; echo "data" >&"${proc[1]}"; read -u "${proc[0]}" result 用于双向管道
  • Here 文档:cat <<-'EOF' 中的 - 会去除行首制表符,引号可阻止展开
  • 进程管理:使用 wait $pid 等待后台任务,使用 jobs -p 列出后台 PID
  • 条件执行:cmd1 && cmd2 仅当 cmd1 成功时运行 cmd2,cmd1 || cmd2 则在 cmd1 失败时运行 cmd2
  • 花括号展开:touch file{1..10}.txt 可高效创建多个文件
  • Nameref 变量:declare -n ref=varname 创建对另一个变量的引用(Bash 4.3+)
  • 改进错误捕获:使用 set -Eeuo pipefail; shopt -s inherit_errexit 进行全面的错误处理
  • 并行执行:xargs -P $(nproc) -n 1 command 使用 CPU 核心数进行并行处理
  • 结构化输出:使用 jq -n --arg key "$value" '{key: $key}' 生成 JSON
  • 性能分析:使用 time -v 查看详细的资源用量,或使用 TIMEFORMAT 自定义计时格式

参考资料与延伸阅读

风格指南与最佳实践
工具与框架
  • ShellCheck - 静态分析工具,附有详尽的 Wiki 文档
  • shfmt - Shell 脚本格式化工具,附有详细的标志说明
  • bats-core - 持续维护的 Bash 测试框架
  • shellspec - 面向 Shell 脚本的 BDD 风格测试框架
  • bashly - 现代 Bash CLI 框架生成器
  • shdoc - Shell 脚本文档生成器
安全与高级主题

示例

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
task_tmpdir=$(mktemp -d) || exit 1
trap 'rm -rf -- "$task_tmpdir"' EXIT
printf '%s\n' 'example' > "$task_tmpdir/input.txt"
[[ -s "$task_tmpdir/input.txt" ]] || exit 1

目录会在安装清理逻辑之前创建。删除前,请对已批准的路径进行引用或验证:-- 会停止选项解析,但无法避免误删错误的绝对路径。严格模式和 ERR 陷阱也无法捕获所有上下文中的失败。

限制

  • 仅当任务明确符合上述范围时,才使用此技能。
  • 不要将输出视为针对特定环境进行验证、测试或专家审查的替代方案。
  • 如果缺少必要的输入、权限、安全边界或成功标准,请停止并请求澄清。

主要支持的语言:CodeQL 支持的语言。

评论

支持 Markdown