rm 是什么
rm 删除的是目录项:把文件的硬链接计数减 1,只有当计数归零、且没有任何进程仍持有该文件的句柄时,内核才回收 inode 与数据块。这一层机制解释了三个常见现象——删除几十 GB 的大文件几乎瞬间完成,因为只改目录项;rm 之后 df 却不下降,因为还有进程持有句柄;以及 rm 没有回收站,链接一旦断开,数据块的寻回就只能靠文件系统级的恢复工具。
基本信息
| 适用平台 | Linux 全发行版与 macOS(GNU coreutils / BSD rm;-I 与 --preserve-root 属于 GNU 扩展) |
|---|---|
| 命令语法 | rm [选项] 文件...;可一次传多个文件或目录 |
| 常用选项 | -r/-R 递归删除目录、-f 强制(忽略不存在的文件、不询问)、-i 逐个询问、-I 递归或超过三个文件时询问一次、-d 删除空目录、-v 显示过程 |
| 权限要求 | 能否删除取决于父目录的写与执行权限,与文件自身的权限无关;目录带 sticky 位时(如 /tmp)只能删除自己拥有的文件 |
| 安全默认 | GNU 版默认启用 --preserve-root,拒绝对 / 递归执行删除 |
典型使用场景
- 清理临时产物:构建缓存、解压中间目录、下载的安装包用完即删
- 清空目录内容但保留目录本身与属主,例如发布前清空站点目录
- 按条件清理日志:比起 rm 通配符,find 加 -delete 能按时间与大小精确圈定范围
- 脚本收尾:trap 里删除自己创建的临时目录,避免残留
- 卸载前清理:确认服务已停止再删数据目录,删除前先做一份备份
- 空间回收前的预处理:把待删目录先 mv 到回收目录,观察一段时间再真正删除
常用示例
常用示例
rm -i important.conf # 逐个询问,适合手工操作
rm -rf /tmp/build-cache # 递归强制删除目录
rm -v *.tmp # 显示删除过程
rm -I -rf /data/old/* # 递归前只问一次,兼顾效率与安全
find /var/log/app -name '*.log.1' -delete # 按条件安全清理
rm -rf -- -weird-name # -- 结束选项解析,处理以 - 开头的名字防误删脚本模板
防误删脚本模板
set -u # 未定义变量直接报错,避免空变量展开
DIR=/tmp/clear-target
[ -n "$DIR" ] && [ "$DIR" != / ] || exit 1
printf '即将删除:%s\n' "$DIR" # 先打印再动手
find "$DIR" -mindepth 1 -delete # 逐项删除,可控且留痕
# 更稳的做法:mv 到回收目录,确认无误后再清
# mv "$DIR" /tmp/trash-$(date +%F)/选项对照
| 选项 | 作用 | 使用建议 |
|---|---|---|
| -i | 每个文件都询问一次 | 手工小批量操作;批量场景会被问到手酸 |
| -I | 递归或超过三个文件时只问一次 | 比 -i 实用,脚本与手工都适合 |
| -f | 不询问、忽略不存在的文件,并把退出码正常化 | 与 -r 组合最危险,务必先确认路径 |
| -r | 递归删除目录及其内容 | 不跟随符号链接去删目标,删的是链接本身 |
| -d | 删除空目录 | 等价 rmdir,非空目录会报错 |
| --preserve-root | 拒绝对 / 递归操作 | GNU 默认开启,不要用 --no-preserve-root 绕过 |
用 rm -rf 目录内容时,通配符 * 不匹配以点开头的隐藏文件,容易造成「清不干净」;要彻底清空用 find 目录 -mindepth 1 -delete,或在确认目录无隐藏文件风险后配合 dotglob 使用。
删除量非常大时 rm -rf 可能报 Argument list too long(命令行参数长度超限),这不是权限问题。改用 find 目录 -delete 或 xargs 分批处理即可绕开参数上限。
Linux 没有回收站。ext4 等文件系统上,误删后若未发生新的写入,可用 debugfs 或 extundelete 尝试恢复,但成功率取决于数据块是否已被覆盖。与其事后恢复,不如把「先 mv 到 /tmp/trash-日期 目录、观察一段时间再删」固化成习惯。