Linux 禁用 rm 等危险命令,防止误操作
在服务器上敲错一个 rm -rf 的代价可能是一整块数据盘。与其事后恢复,不如提前把 rm 这类高危命令在 shell 层面拦住。这篇用 alias 做两层防护:把 rm 换成无害提示,再用”回收站 + 定时清理”兜住真要删的场景,顺带把 shutdown/reboot 这类误触即发火的命令一并禁掉。所有行为在 Rocky 9 容器实测,过程中挖出三个方案自带的坑(嵌套拦截、清理周期语义、root 默认别名覆盖),逐个给出修正。
实验环境
- Rocky Linux 9.3 一次性容器,bash 5.1.8、findutils 4.8.0;
- alias 只在交互 shell 里展开,实测用普通用户 + 登录 shell(
bash -l)模拟日常终端——非登录的交互 shell 不加载 /etc/profile,别名不会生效,这是实测踩到的第一个细节,写进方案前必须确认自己测的是哪种 shell; /etc/profile对登录 shell 生效、影响所有用户;~/.bashrc对每个交互 shell 生效、只影响单个用户。全机拦截用 profile,只管住自己用 bashrc。
核心机制一句话:alias 是 shell 的命令替换,发生在回车解释阶段——它防的是人手滑,脚本和定时任务完全不受它管。
实例一:拦截 rm
编辑 /etc/profile,结尾添加:
1 | ###### rm prevent ###### |
重新登录(或 source /etc/profile)生效。实测:敲 rm 后文件原封不动,只打印一句提示:

这里还有一个实测挖出的坑:Rocky 9 的 root 用户 ~/.bashrc 自带 alias rm='rm -i',登录时它在 /etc/profile 之后加载,会把全局拦截覆盖回交互确认。给 root 也上拦截的话,把这行从 root 的 .bashrc 里删掉,或者干脆用普通账号 + sudo 的方式运维,让全局 alias 真正落到 root 头上。
上线前花一分钟验证:任意用户的终端跑 alias rm,应输出 alias rm='echo can not use rm command';再用 type rmf 看展开链,有没有嵌套别名一眼就能看穿。灰度顺序建议先在测试账号的 .bashrc 试一轮,确认交互习惯没被过度打扰,再推全机 profile。
实例二:保险删除 rmf
文件拦下来不是目的,生产上总归有要删的时候——把”删”改成”挪 + 定期清”:要删的文件先挪进回收站目录(如 /data/recycleDir/),确认删除用另一个别名并保留交互确认:
1 | # 确认真的要删(保留 -i 交互确认) |
这个写法在拦截生效的环境下是坏的。实测 alias rmf="rm -i" 后执行 rmf,alias 展开是递归的:rmf → rm -i → rm 又被第一条 alias 拦截,最后输出的是那句提示,文件原地不动——保险删除自己删不了文件:

修正:用绝对路径绕过 alias 展开:
1 | # 修正写法 |
修正后输入 y 才真删,输入 n 保留,交互确认回来了。日常”删”文件的动作则变成 mv /data/app/old.log /data/recycleDir/。
实例三:回收站与定时清理
配套的清理脚本 /data/scripts/del.sh,按周期清扫回收站里放够久的文件。回收站目录先建好并给足权限:
1 | mkdir -p /data/recycleDir |
1777 与 /tmp 同款:带 sticky 位,多人共用的机器上人人可放文件、但删不了别人的,回收站不会被误清。清理脚本本体:
1 |
|
先说脚本里的两个实测修正。其一,alias 在脚本(非交互 shell)里默认不展开:脚本里写 | xargs rmf -f 实测报 xargs: rmf: No such file or directory,清理动作静默失效,所以 del.sh 必须写完整命令 /bin/rm -f。
其二,周期单位别照抄老脚本的 -mtime +48。它的语义不是”48 小时”,而是”修改时间在 49 个完整天之前”(find 按天取整再比较)。实测一个 49 小时前修改的文件:-mtime +48 捞不到它,-mmin +2880(2880 分钟 = 48 小时)能捞到;50 天前的文件两者都能捞到:

按业务周期选好单位后,用 crontab 挂上定时执行(每天凌晨 1 点清一次):
1 | 0 1 * * * /bin/sh /data/scripts/del.sh |
挂 crontab 前先手动跑一遍 sh /data/scripts/del.sh,再 ls /data/recycleDir/ 确认该清的清掉了、不该清的还在——清理脚本误伤的代价和误删是一样的。真删错了还有最后一道保险:文件刚进回收站、清理任务还没跑时,从 /data/recycleDir/ mv 回原路径即可恢复。
防止误操作关机
思路相同,把关机相关命令也换成空操作:
1 | alias shutdown='' |
这些 alias 同样写在 profile 里。置空的 alias 展开成空命令,敲 reboot 只会安静地回到提示符,什么也不发生;真需要关机重启时,把对应 alias 行注释掉,source 后重新登录终端即可恢复使用。
救急:绕过 alias 用回真 rm
拦截上线后偶尔有必须真删的场景,三个办法按快慢排序:
1 | \rm file # 反斜杠跳过 alias |
这三个办法也意味着拦截形同虚设——防的是”习惯性手滑”,拦不住”执意要删”,所以回收站兜底层不可省。另一个互补思路是 chattr +i 给关键文件上不可变位,连 root 的 rm 都会被内核拒绝(文件系统层防护,与 alias 层各管一段);本次容器环境缺少相应内核能力未能实测,实机用法见 chattr(1) 手册。
错误写法对比
错误一:指望 alias 保护脚本。定时脚本、ssh host 'rm ...' 这类非交互调用都不走 alias,拦截不存在——alias 方案只防交互手滑。
错误二:rmf='rm -i' 嵌套在拦截之下。展开链 rmf → rm -i → echo can not...,确认删除失效(实例二已实测),必须写 /bin/rm -i。
错误三:清理周期用 -mtime 按小时想。-mtime +48 删不到 49 小时前的文件(实例三已实测),要按小时/分钟控制就写 -mmin +2880。
错误四:root 的默认别名没处理。root ~/.bashrc 自带 alias rm='rm -i',加载顺序在 /etc/profile 之后,全局拦截会被它悄悄覆盖(实例一已实测现象),上线前逐用户核对 alias rm 的实际取值。
注意事项
- alias 只对交互 shell 生效,脚本和远程单命令调用不受影响,它防的是手滑,不是权限漏洞。
sudo rm不经过当前 shell 的 alias 展开,拦截对 sudo 调用同样无效。- 禁用 rm 的方案要和回收站清理脚本配套,否则 /data/recycleDir/ 只进不出,早晚撑爆磁盘。
- 清理周期确认用
-mmin +N(分钟)还是-mtime +N(天),两者语义差一个量级。 - 改 /etc/profile 影响所有用户,先在测试机用普通用户验证
alias rm、alias rmf的实际取值,再下发生产。
小结
回到开场的 rm -rf:alias 拦截让它发不出去,rmf 保险删除(绝对路径写法)留一道确认,回收站加定时清理兜住”真要删”的场景——三层下来,手滑的代价从”一整块数据盘”降为”去回收站捞一下”。三处实测修正(/bin/rm -i、-mmin +2880、root 默认别名)记得同步进你的脚本,方案才真正闭环。
本文由作者 2020-2024 年间的 CSDN 博客文章重构而来,原发布于 CSDN。