跳转到内容

rm

rm(remove)用于删除文件和目录。没有回收站,删掉就是删掉了,所以这条命令的重点不在选项,而在怎么不删错。

Terminal window
rm [选项] 文件...

默认只删文件,删目录要加 -r 默认不会问,删成功也没有任何输出

rm 调的是 unlink,删掉的是目录项,也就是那个文件名,同时把 inode 的链接数减一。只有链接数降到 0、并且没有任何进程还打开着这个文件时,数据块才会被回收。

由此有三个实际后果:

  • 文件有硬链接时,删掉一个名字内容还在,剩下的名字照样能读,见 ln
  • 删掉一个正被进程打开的文件,磁盘空间不会立刻回来,要等进程退出;lsof +L1 能查出这类文件
  • 数据块只是被标记为可用,并没有擦除,所以恢复理论上可能 —— 但只要还在写盘就随时会被覆盖,别指望
选项 说明
-r 递归删除目录及其内容(recursive),-R 等价
-f 强制(force),文件不存在也不报错,不做任何提示
-i 每个文件都问一次(interactive)
-I 删三个以上文件、或带 -r 时,统一问一次
-d 删除空目录(directory),相当于 rmdir
-v 打印每一个被删掉的文件(verbose)
--one-file-system 递归时不越过文件系统边界,配合 -rf 能挡住一类事故
--preserve-root 拒绝对 / 动手,默认就是开的

1. 删文件和目录

Terminal window
rm a.txt
rm -r dir/
rm -rf dir/ # 目录不存在也静默返回成功

2. -I 比 -i 更有用

Terminal window
rm -I *.log

-i 是每个文件问一次,几十个文件时只会让人一路按 y,防护等于不存在 -I 只在数量超过三个或递归删除时问一次,这一次才会真的看一眼

3. 变量为空是最常见的事故

Terminal window
rm -rf $dir/build # $dir 为空时展开成 rm -rf /build
rm -rf "${dir:?未设置}" # 变量为空直接报错退出,不执行

路径变量一律加引号,:? 让空值变成一次失败而不是一次删除 引号也管空格:rm -rf "/var/log /tmp" 是一个不存在的路径,而不是两个目标

4. 文件名以 - 开头

Terminal window
rm -- -weird.txt
rm ./-weird.txt

- 开头会被当成选项,用 -- 结束选项解析,或者给个 ./ 前缀

5. 按条件批量删

Terminal window
find . -name '*.tmp' -print # 先看要删什么
find . -name '*.tmp' -delete # 确认无误再删

-delete 由 find 自己完成,不经过 shell,文件名再古怪也不会被拆错 习惯是先用 -print 跑一遍,确认列表对了再把它换成 -delete