mcpField
L
linux-bash-scripting

linux-bash-scripting

github.com/iliaal开发45180 次安装3 天前更新
代码仓库

关于 linux-bash-scripting

一项用于编写和验证面向 Linux 上 GNU Bash 4.4+ 的 Bash 脚本的技能。它为开发者提供输入安全、文件操作和性能方面的实践,并要求在完成前运行 ShellCheck 与 shfmt 检查。

主要功能

  1. 01面向 Linux 上的 GNU Bash 4.4+
  2. 02规范输入与进程安全处理
  3. 03涵盖文件、密钥和清理
  4. 04使用 ShellCheck 与 shfmt 验证
  5. 05提供语法检查备用方案

适用场景

  1. 01编写 Linux 自动化脚本
  2. 02处理不可信输入与子进程
  3. 03交付前检查脚本

安装

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

$npx skills add https://github.com/iliaal/ai-skills --skill linux-bash-scripting

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

SPEC.md
references/
input-and-process-safety.md
production-patterns.md

详细介绍

Linux Bash 脚本

编写 Bash 脚本,使其通过 shellcheck --enable=all 和 shfmt -d 检查且没有任何警告。

目标环境:Linux 上的 GNU Bash 4.4+。不提供 macOS/BSD 兼容处理,不使用 Windows 路径,也不受 POSIX 专属限制。

脚本基础

#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s inherit_errexit

SCRIPT_DIR=$(dirname -- "${BASH_SOURCE[0]}") || exit "$?"
SCRIPT_DIR=$(cd -- "${SCRIPT_DIR}" && pwd -P) || exit "$?"
readonly SCRIPT_DIR

trap 'printf "Error at %s:%d\n" "${BASH_SOURCE[0]}" "$LINENO" >&2' ERR
trap 'rm -rf -- "${_tmpdir:-}"' EXIT
  • -E 会将 ERR 陷阱传播到函数中
  • inherit_errexit 会将 errexit 传播到 $() 命令替换中
  • 根据 SCRIPT_DIR 解析脚本自身的数据文件,绝不依赖调用者的当前工作目录或 git rev-parse --show-toplevel。从其他项目的 Git hook、cron 作业或包装脚本调用共享的代码检查器时,当前工作目录属于其他项目,因此调用者相对的规则路径会指向不存在的文件:规则集为空,未发现违规项,退出状态为 0。这是静默无操作,并非错误;而且在其自身仓库中运行时,会因为错误的原因而通过。请从脚本自身目录树以外的临时目录运行一次
  • 始终在 EXIT 陷阱中创建临时目录:_tmpdir=$(mktemp -d)
  • 将主体放在 main 函数中。保护其调用逻辑,使直接执行时运行该函数,而 source 时仅定义函数以供测试。

核心规则

  • 为展开内容加引号,使用数组表示命令,绝不将外部数据作为 Shell 代码执行。
  • 在算术运算前,验证数字语法、正负号和应用范围。对无符号数字先使用 10# 转换,再应用正负号;10#-08 无效。
  • 不要将密钥放入进程参数或跟踪输出中。通过 stdin 传入,并使用支持 JSON 的编码器。
  • 在“缺失”和“检查失败”含义不同时,检查准确的退出状态。将 local 和 readonly 声明与命令替换分开。
  • 使用 NUL 分隔的文件迭代,验证必需的标志值,并拒绝互相冲突的输出/目标组合。
  • 原子替换时,在目标文件旁暂存;激活多个文件时,切换单个已暂存的发布引用。
  • 保留无关文件,并在清理后报告实际的信号或命令状态。
  • 不要假设 Bash 选项在 sh 中也有效,不要假设 GNU 工具模式的行为等同于系统调用模式,也不要假设已配置的回退路径可用。

特定任务参考资料

实施相应行为前,请阅读相关参考资料:

  • 对于命令执行、外部输入、数字转换、参数解析、迭代或子进程状态处理:input-and-process-safety.md。
  • 对于文件激活、密钥、锁、重试、清理、权限、日志记录或可重启自动化:production-patterns.md。

性能

  • 对外部程序使用参数展开:${path%/*} 代替 dirname,${path##*/} 代替 basename,${var//old/new} 代替 sed
  • 使用 (( )) 代替 expr;使用 [[ =~ ]] 代替 echo | grep
  • 缓存结果:val=$(cmd) 执行一次,重复使用 $val
  • 使用 xargs -0 -P "$(nproc)" 并行处理
  • 使用 declare -A map 进行查找,代替反复调用 grep

Bash 4.4+ / 5.x

  • ${var@Q} 会添加 Shell 引号(Bash 4.4+);${var@U} 转为大写,${var@L} 转为小写(Bash 5.1+)
  • declare -n ref=varname 使用 nameref 进行间接访问
  • wait -n 等待任意一个后台作业
  • $EPOCHSECONDS、$EPOCHREALTIME:无需派生 date 即可获取时间戳(Bash 5.0+)

Linux 专属

  • GNU coreutils 与 macOS 不同:sed -i(不带 '' 后缀)、grep -P(支持 PCRE)、readlink -f(规范路径)
  • 使用 timeout 30s cmd 防止自动化任务挂起
  • sed -i 会将符号链接替换为普通文件:它会写入临时文件并将其重命名到原路径,因此之后两份文件会分开变化,且不会报错。请使用 sed -i --follow-symlinks 或按名称编辑目标文件,并在脚本化编辑后检查 git status --short 是否出现 T(类型更改)

ShellCheck

运行 shellcheck --enable=all script.sh。重要规则:

  • SC2155:将声明与赋值分开
  • SC2086:为变量添加双引号
  • SC2046:为命令替换添加引号
  • SC2164:使用 cd dir || exit
  • SC2327/SC2328:确保命令替换仍可访问标准输出;将其重定向到其他位置会导致捕获的值为空
  • 从 ${BASH_REMATCH[n]} 读取正则表达式捕获结果,而不是从位置参数读取

提交前检查:shellcheck *.sh && shfmt -i 2 -ci -d *.sh

验证

在声明完成之前,运行 shellcheck --enable=all 和 shfmt -d,确保没有警告。测试边缘情况:空输入、缺失文件、路径中包含空格。

如果未安装 shellcheck 或 shfmt(command -v shellcheck 失败),则表示检查已跳过,而不是通过:报告“未运行静态分析:shellcheck 不可用”,并回退到仅用于语法检查的 bash -n。跳过的检查器与上方的空规则文件一样,都是悄无声息地不执行任何操作。

评论

支持 Markdown