本来一开始没想写这个文章,因为有点过于丢人了。但是我之前一直推荐大家用OpenClaw,我都翻车了还是本着负责任的态度说说。

之前有个事故,OpenClaw 在执行清理任务的时候跑了一行 rm -rf ~/,没加引号,Shell 直接把 ~ 展开成 /Users/zhheo/,然后整个用户目录就开始被递归删除。

玩梗的段子回旋镖来了

等我发现的时候,Desktop、Music、Pictures 这些文件夹已经没了。好在有极空间 NAS 的 Syncthing 同步,大部分文件恢复了回来,但那个心惊胆战的感觉是真的不好受。

所以这次我给 .zshrc 里的 rm 函数加了一层硬保护。

两层防护

第一层:危险路径拦截

不管你是 rm -rf ~/ 还是 rm -rf /Users/zhheo,只要目标是用户主目录,直接拦截不执行。Shell 展开 ~ 之后变成绝对路径,函数里有一份危险路径黑名单,命中就报错退出。

第二层:受保护目录

Desktop、Documents、Downloads、Music、Movies、Pictures、.ssh、.openclaw、.config 这些目录,rm -rf 直接拦截。精确匹配,rm -rf ~/Music 会被拦。

其他递归删除(比如 rm -rf ~/Music/some_folder)不会被拦截,但会自动转成 trash,文件进废纸篓可恢复。只有非递归的单文件删除才走系统原生 rm

怎么实现的

.zshrc 里定义了一个 rm() 函数,覆盖系统的 rm 命令。逻辑很简单:

1
2
3
4
5
6
7
rm() {
# 1. 解析参数,判断是否 -r/-R
# 2. 检查目标路径是否在危险列表/保护目录里
# 3. 命中 → 报错退出
# 4. 没命中且是递归删除 → 自动转 trash
# 5. 普通删除 → 正常 rm
}

递归删除全部自动转 trash,文件进废纸篓还能恢复。只有非递归的 rm(比如删单个文件)才走系统原生命令。

测试结果

1
2
3
$ rm -rf ~/
🚫 危险操作已拦截:rm /Users/zhheo/
这会删除整个用户目录!
1
2
3
$ rm -rf ~/Music
🚫 受保护目录,禁止递归删除:/Users/zhheo/Music
如需删除请用 trash 命令手动操作

要加减保护目录的话随时说,改 .zshrc 就行。

其他 OpenClaw 用户怎么用

把下面这段加到你的 ~/.zshrc 里就行(代码仅适用于mac,建议发给你的龙虾帮你添加代码,因为代码可能需要根据环境定制修改)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# rm 安全函数:递归删除自动转 trash,危险路径直接拦截
rm() {
local has_recursive=false
local files=()
for arg in "$@"; do
case "$arg" in
-r*|-R*) has_recursive=true ;;
-f*|-i*|-v*|-I*) ;;
--*) ;;
-*) ;;
*) files+=("$arg") ;;
esac
done

# 保护目录列表(递归删除直接拦截)
local protected_dirs=(
"$HOME/Desktop"
"$HOME/Documents"
"$HOME/Downloads"
"$HOME/Music"
"$HOME/Movies"
"$HOME/Pictures"
"$HOME/.ssh"
"$HOME/.openclaw"
"$HOME/.config"
)
if $has_recursive; then
for f in "${files[@]}"; do
for pd in "${protected_dirs[@]}"; do
if [[ "$f" == "$pd" || "$f" == "$pd/" ]]; then
echo "🚫 受保护目录,禁止递归删除:$f" >&2
echo " 如需删除请用 trash 命令手动操作" >&2
return 1
fi
done
done
fi

# 危险路径拦截
local dangerous_paths=(
"/Users/zhheo"
"/Users/zhheo/"
"$HOME"
"$HOME/"
"/"
"/root"
"/home"
)
for f in "${files[@]}"; do
for dp in "${dangerous_paths[@]}"; do
if [[ "$f" == "$dp" || "$f" == "$dp/" ]]; then
echo "🚫 危险操作已拦截:rm $f" >&2
echo " 这会删除整个用户目录!" >&2
return 1
fi
done
done

if $has_recursive; then
for f in "${files[@]}"; do
trash "$f" 2>/dev/null || echo "⚠️ 无法移到废纸篓: $f" >&2
done
else
command rm "$@"
fi
}

protected_dirs 里可以加你自己的目录,比如项目文件夹、数据库目录之类的。改完跑 source ~/.zshrc 就生效。