Linux 中 rm 命令详解

当你在终端里清理旧日志、构建产物或临时文件时,通常第一个想到的命令就是 rm。它从文件系统中删除文件和目录,而且是永久删除,并不会把文件送进桌面的回收站文件夹。

本指南通过实用示例讲解如何在 Linux 中使用 rm 命令,包括递归删除目录、确认提示、通配符匹配,以及更安全地使用 rm -rf 的方法。

rm 命令语法

rm 命令的通用语法如下:

rm [OPTIONS] FILE...

默认情况下,rm 不会删除目录,并且在删除文件之前不会提示确认。

常用 rm 选项

最常用的 rm 选项用于控制递归、提示和输出:

  • -f, --force — 忽略不存在的文件,且从不提示确认。
  • -i — 每次删除前都提示确认。
  • -I — 在删除超过三个文件、或执行递归删除之前,只提示一次。
  • -r, -R, --recursive — 递归删除目录及其内容。
  • -d, --dir — 删除空目录。
  • -v, --verbose — 在删除发生时打印每个被移除的条目。
  • --interactive=WHEN — 将提示行为设为 never(从不)、once(一次)或 always(总是)。
  • --one-file-system — 递归删除时,跳过位于不同文件系统中的目录。
  • --preserve-root — 拒绝删除 /,这是 GNU rm 的默认保护。

你可以组合使用短选项。例如,rm -rv dirname 会递归删除一个目录,并打印每一个被移除的路径。

删除单个文件

要删除单个文件,把文件名作为参数传入即可:

rm filename

如果文件没有写保护,rm 会静默删除它,不输出任何内容。删除成功时,rm 返回退出码 0。

如果你对父目录没有写和执行权限,rm 会失败并报「Permission denied(权限被拒绝)」错误。「Operation not permitted(操作不被允许)」则指向另一种原因:要么父目录设置了 sticky 位且该文件属于其他用户(/tmp 正是靠这种方式保护自己的内容),要么该文件是不可变的(immutable)。

当删除一个写保护文件时,rm 会提示确认:

rm: remove write-protected regular empty file 'filename'?

输入 y 并按回车确认。

要跳过提示、不经确认直接删除文件,使用 -f(force,强制)选项:

rm -f filename

-f 还会静默忽略不存在的文件,而不是返回错误。

要看到每个文件被删除的过程,使用 -v(verbose,详细)选项:

rm -v filename
removed 'filename'

详细输出在一条命令匹配了多个文件、而你想记录究竟删除了什么时非常有用。

删除多个文件

与 unlink 命令不同,rm 可以一次接受多个文件名:

rm filename1 filename2 filename3

你也可以使用 shell 的通配符来匹配多个文件。例如,要删除当前目录下所有 .png 文件:

rm *.png

在运行带通配符的 rm 之前,先用 ls 预览一下会匹配到哪些文件:

ls *.png

shell 会在 rm 运行之前展开 *.png。如果通配模式匹配到的文件比预期多,在真正删除任何东西之前先调整模式。

删除目录

要删除一个或多个空目录,使用 -d 选项:

rm -d dirname

rm -d 在功能上等同于 rmdir 命令。

要递归删除一个非空目录及其全部内容,使用 -r(recursive,递归)选项:

rm -r dirname

这会删除该目录及其内部的一切,包括文件、子目录和符号链接。

删除前确认提示

-i 选项会在删除每个文件之前提示确认:

rm -i filename1 filename2
rm: remove regular empty file 'filename1'?
rm: remove regular empty file 'filename2'?

输入 y 并按回车逐个确认每个文件。

当删除超过三个文件、或递归删除一个目录时,使用 -I(大写)选项,针对整个操作只给一次提示,而不是每个文件一次:

rm -I filename1 filename2 filename3 filename4
rm: remove 4 arguments?

rm -rf

组合 -r 和 -f 会删除一个目录及其全部内容,且全程不提示,即便目录内的文件是写保护的也不例外:

rm -rf dirname

短选项的先后顺序无关紧要,所以 rm -fr dirname 与 rm -rf dirname 效果完全相同。

警告:rm -rf 是永久且不可逆的。运行前务必再三确认路径。绝不要运行 rm -rf / 或 rm -rf /*,因为那会尝试删除整个文件系统。现代 Linux 系统默认会拦截 rm -rf /,但这种保护并不覆盖所有变体。

在使用脚本中的变量时,先打印目标路径确认,或先用 ls 测试一下。这有助于在变量为空或取值异常时,赶在它们被传给 rm -rf 之前发现问题。

删除以短横线开头的文件

以 - 开头的文件名会被 rm 当作选项来解析。要删除这类文件,用 -- 表示选项的结束:

rm -- -filename

另一种方式是在路径前加上 ./ :

rm ./-filename

速查表

要获取一份可打印的速查表,请参阅 rm 备忘单。

任务命令
删除一个文件rm file
删除且不提示rm -f file
显示详细输出rm -v file
删除多个文件rm file1 file2 file3
按通配符删除rm *.log
删除空目录rm -d dir
递归删除目录rm -r dir
递归删除且不提示rm -rf dir
递归并显示详细rm -rv dir
删除每个文件前提示rm -i file
删除多个文件只提示一次rm -I file1 file2 ...
删除以 - 开头的文件rm -- -filename
按名称控制提示行为rm --interactive=once file1 file2

故障排查

「操作不被允许(Operation not permitted)」:父目录设置了 sticky 位,且该文件属于另一个用户——这正是 /tmp 阻止一个用户删除其他用户文件的方式;或者该文件是不可变的。用 ls -ld dirname 检查目录,用 lsattr filename 检查文件,只有在确实需要 root 权限时才使用 sudo。

「权限被拒绝(Permission denied)」:父目录的权限通常决定了你能否删除其中的条目。用 ls -ld dirname 检查目录,再视情况用 chmod 调整权限或用 chown 调整归属。

「cannot remove 'dirname': Is a directory(无法删除 'dirname':是一个目录)」:rm 需要 -r 标志才能删除目录。请改用 rm -r dirname。

「cannot remove 'file': No such file or directory(无法删除 'file':没有那个文件或目录)」:文件不存在或路径不正确。用 ls 核实路径。要在脚本中抑制这个错误,使用 rm -f。

「写保护文件未被删除」:没有 -f 时,rm 会在删除写保护文件前提示。要么输入 y 确认,要么用 rm -f 跳过提示。

「不可变文件无法删除」:在支持文件属性的 Linux 文件系统上,不可变文件即使 root 也无法删除,直到清除该属性。用 lsattr filename 检查,只有在确定该文件确实应该删除时,才用 sudo chattr -i filename 移除不可变标志。

「设备或资源忙(Device or resource busy)」:该路径可能是挂载点,或有进程正在使用这个目录。在重试之前,先用 findmnt 检查已挂载的文件系统,用 lsof +D dirname 查看该路径的活跃使用者。

常见问题(FAQ)

用 rm 删除的文件能恢复吗?不容易。rm 会立即移除文件系统条目,而不会把文件移到回收站文件夹。在 ext4 上可以借助 extundelete 或 testdisk 等工具尝试恢复,但能否成功取决于磁盘块是否已被覆盖。更安全的做法是使用 trash-cli 这类回收站工具(trash file 会把文件移到 ~/.local/share/Trash)。

rm 和 unlink 有什么区别?unlink 通过直接调用 unlink 系统调用来删除单个文件。rm 是更高层的工具,支持多文件、目录、通配符和交互式提示。

如何删除一个目录里的所有文件,但保留目录本身?用 rm -rf dirname/* 删除非隐藏内容,同时保留目录本身。像 * 这样的 shell 通配符默认不匹配隐藏的点文件。要在不删除父目录的前提下清除隐藏和非隐藏内容,先核实路径,再用 find dirname -mindepth 1 -delete。

rm -rf / 危险吗?是的。它会尝试删除文件系统中的一切。现代 Linux 系统默认通过 --preserve-root 保护机制拦截它,但像 rm -rf /* 这样的变体、或显式指定挂载的根路径,并不总是受保护。永远不要运行这条命令。

如何删除超过 N 天的文件?使用 find 命令:find /path -type f -mtime +30 -delete 会删除最近 30 天内未被修改的文件。

总结

在执行任何 rm -rf 之前,先用 ls 对同样的路径跑一遍,尤其是涉及变量时。对于频繁清理构建产物或日志的场景,可以把 rm 别名设为 trash-cli 的 trash 命令,这样误删也能恢复。