shell-scripting-safelisted
Install: claude install-skill Wade-DevCode/awesome-coding-skills-cn
# Shell 脚本安全
## 何时用
- 新写或修改任何 `.sh` / bash 脚本。
- 脚本涉及文件删除、目录覆盖、远程操作等危险步骤时。
- 发现脚本某步骤出错后默默继续、没有任何输出时。
- 把手动运维步骤固化成自动化脚本前做方案设计。
## 核心规则
### 1. 头部加 `set -euo pipefail`,让错误立即暴露
**规则:** 每个脚本第一行(shebang 之后)加 `set -euo pipefail`,确保命令非零退出立即终止脚本(`-e`),引用未定义变量报错(`-u`),管道中间命令失败也能被捕获(`-o pipefail`)。
**为什么���** AI 生成的 bash 脚本默认不加这三个选项,导致静默失败危害极大。曾见真实事故:`TARGET_DIR=""` 变量赋值失败(来自上一条命令出错),下一步 `rm -rf "$TARGET_DIR/"` 展开为 `rm -rf "/"` 并成功执行——因为没有 `-u`,空变量不报错;因为没有 `-e`,上一步出错没停下来。加上这三行,相同场景会在变量赋值处立即报错退出。
**怎么做:**
```bash
#!/usr/bin/env bash
set -euo pipefail
# 之后的所有命令:任何一步失败即停止,未定义变量即报错
```
- 若某条命令允许失败,用 `command || true` 或 `command || echo "可选步骤失败,继续"` 显式豁免,不要关掉全局 `-e`。
- 子 shell 调用的脚本同样需要各自设置,不继承父脚本的 `set` 选项。
---
### 2. 变量永远加双引号
**规则:** 引用任何变量时都用双引号:`"$var"`、`"$@"`、`"${array[@]}"`;只在明确需要分词或通配符展开时才省略引号。
**为什么:** AI 写 bash 时很少给变量加引号,遇到含空格或通配符的路径时立刻出事。典型案例:`cp $SRC $DST` 在 `SRC="/home/user/my files/data.txt"` 时被 shell 解析为 `cp /home/user/my files/data.txt $DST`,变成三个参数,`cp` 报错或拷错文件。更危险的是 `rm -rf $DIR/*`,若 `DIR` 是 `/tmp/app `(带尾随空格),展开结果不可预料。
**怎么做:**
```bash
# 反例
cp $SRC $DST
rm -rf $DIR/*
# 正例
cp "$SRC" "$DST"
rm -rf "${DIR:?}/"* # :? 额外保证变量非空,空则报错退出
```
- 数组展开用 `"${arr[@]}"` 而非 `${arr[*]}`,保留每个元素的边界。
- 命令替换也加引号:`output="$(some_command)"`。
---
### 3. 危险操作前校验变量非空与路径合法,提供 dry-run
**规则:** 执行 `rm -rf`、`dd`、`mkfs`、大范围覆盖等不可逆操作前,必须:① 用 `${VAR:?错误信息}` 或显式 `if [ -z "$VAR" ]` 校验关键变量非空,② 检查路径符合预期(不是根目录、不是系统目录),③ 支持 `DRY_RUN=1` 模式只打印不执行。
**为什么:** AI 生成的清理脚本几乎从不做这类防御,使用者一旦环境变量配置错误,`rm -