
命令行是一个强大的工具,能让你比图形界面更快、更高效地完成日常任务。但如果使用不当,它同样很危险——在从系统中删除不必要的文件或目录时尤其如此。
桌面用户可以使用图形界面轻松删除文件,并在需要时从回收站恢复这些文件。但如果你使用的是无图形界面的服务器(headless server),命令行工具能让你借助通配符或其他模式匹配一次性删除多个文件和目录。
本文介绍 Linux 中几种用于删除文件和目录的工具。我们将讲解如何使用 rm、unlink、shred 和 rmdir 命令,如何用 find 批量清理文件,以及如何以「仍可撤销」的方式删除文件。
开始之前
在 Linux 中,有多种工具可用于删除文件和目录。删除文件或目录时务必格外小心,因为文件一旦被删除,即使使用恢复软件也很难找回。
删除一个文件需要对它所在目录拥有写权限和执行权限,而不是对文件本身。这就是为什么——只要你能写入其父目录,即使你不拥有某个只读文件也能删除它;反过来,当父目录对你关闭时,即便你拥有该文件也无济于事。
名称中带空格的文件必须用反斜杠(\)转义,或用引号包裹。
如何在 Linux 中删除文件
在 Linux 中,要从命令行删除(移除)文件,可以使用 rm、shred 或 unlink 命令。
unlink 命令一次只能删除单个文件,而 rm 和 shred 则可以一次删除多个文件。
使用 rm 命令
要删除单个文件,执行 rm 命令并跟上文件名:
rm filename
如果你对父目录没有写权限,命令会失败并报错「Permission denied」(权限被拒绝):
rm: cannot remove 'filename': Permission denied
另一种不同的提示「Operation not permitted」(不允许的操作),指向的是不同的原因。当父目录设置了粘滞位(sticky bit)而文件不属于你时(这正是保护 /tmp 中他人文件的机制),或者文件带有不可变(immutable)属性时,就会看到它。
当文件是写保护的、标准输入是终端、且未使用 -f 时,GNU rm 会要求确认,如下所示。而 -i 选项无论文件权限如何都会逐一提示。要删除文件,输入 y 并按回车键。
rm: remove write-protected regular empty file 'filename'?
要一次性删除多个文件,执行 rm 命令并跟上以空格分隔的多个文件名:
rm filename1 filename2 filename3
你也可以使用 shell 的通配符模式匹配多个文件。例如,要删除当前目录下所有 .pdf 文件,可使用以下命令:
rm *.pdf
在 rm 运行之前,shell 已经把模式展开,因此 rm 收到的是一份现成的名称列表,完全不知道曾经涉及通配符。使用通配符时,先用 ls 命令列出文件,以便在运行 rm 之前看清将要删除哪些文件:
ls *.pdf
给 rm 加上 -i 选项,可在删除每个文件前逐一确认:
rm -i filename1 filename2
即使文件是写保护的,也要在不提示的情况下删除,可给 rm 加上 -f(force,强制)选项:
rm -f filename1 filename2
你还可以组合 rm 的选项。例如,要以详细模式无提示地删除当前目录下所有 .txt 文件,使用以下命令:
rm -fv *.txt
removed 'notes.txt' removed 'report.txt'
每一行都确认一次删除,事后你便得到了一份记录,知道通配符实际匹配了哪些文件。
使用 shred 命令
在 Linux 中删除文件时,实际数据并不会被抹去;被移除的只是引用该文件的 inode(文件的元数据),相应的数据块被标记为可重用。文件内容会一直保留在磁盘上,直到这些空间被新数据覆盖。
shred 命令会反复覆写文件以隐藏其内容,使被删除的文件更难以恢复。
要用 shred 覆写并删除文件,执行该命令并跟上 -u 选项和文件名:
shred -u filename
默认情况下,shred 会用随机数据对文件覆写三遍,然后截断并删除它。加上 -z 选项会在最后用全零覆写一遍,使文件看起来不像是被 shred 处理过:
shred -uz filename
你也可以跟上以空格分隔的多个文件:
shred -u filename1 filename2 filename3
在依赖 shred 之前,先理解它的前提假设。GNU 文档说得很直白:shred 依赖文件系统和硬件原地覆写数据,而许多现代存储并不满足这一点。在 data=journal 模式挂载的 ext3、ext4 文件系统上,在 Btrfs、ZFS 这类写时复制或带快照的文件系统上,在 RAID 阵列、压缩文件系统以及 SSD(其损耗均衡会把写入分散到操作系统无法直接寻址的物理块)上,覆写都可能让原始数据块原封不动。备份与镜像则完全不在它的作用范围内。
在使用默认 data=ordered 或 data=writeback 模式的 ext3、ext4 文件系统上,当底层设备确实原地覆写数据块时,shred -u 才可能有效——这通常指没有快照、镜像或备份的常规机械磁盘。若要求设备上任何内容都无法恢复,真正可靠的做法是从一开始就启用全盘加密,或使用硬盘自带的安全擦除命令。
使用 unlink 命令
要用 unlink 删除文件,执行该命令并跟上要删除的文件名:
unlink filename
命令成功时不输出任何内容,并返回 0。unlink 只接受恰好一个文件操作数,且不能删除目录。和 rm 一样,它自身并不解析通配符;shell 仍会在启动命令前展开未加引号的通配符,因此 unlink *.log 在只有一个名称匹配时会删除该文件,匹配到多个则会失败。不要指望用 unlink 来防范意外的 shell 展开。
使用 find 批量删除文件
rm 作用于你给出的名称,这没问题——直到你想要的那些文件散落在目录树各处,或要用名称以外的条件来界定。find 能按模式、时间、大小或类型筛选文件,然后删除它匹配到的内容。
第一步永远先单独运行搜索。在没有任何动作时,find 只会打印匹配结果,这个预览能以最低成本帮你发现表达式范围比预期更宽的问题:
find /var/log/app -type f -name '*.log'
确认列表无误后,再加上 -delete 作为最后一步动作:
find /var/log/app -type f -name '*.log' -delete
下面逐段拆解上面的命令:
- /var/log/app —— 要搜索的目录,包含其下所有内容。
- -type f —— 将匹配范围限制为普通文件,目录不会被波及。
- -name '*.log' —— 只匹配以 .log 结尾的名称。引号阻止 shell 展开该模式,使 find 原样收到它。
- -delete —— 删除每一个匹配到的文件。
按时间删除是另一种常见清理方式。-mtime 测试统计文件最后一次修改以来经过的完整 24 小时周期数。由于 find 在比较前会把时间向下取整,+30 会在经过 31 个完整 24 小时周期后才开始匹配:
find /backups -type f -mtime +30 -delete
若要更精细地控制,可用 -mmin 改以完整分钟计,因此 -mmin +90 会在经过 91 个完整分钟之后才开始匹配。
你也可以按大小删除。下面会删除 /var/tmp 下所有大于 1 GB 的文件:
find /var/tmp -type f -size +1G -delete
-delete 不属于 POSIX 规范,因此部分非 GNU 实现并不提供它,而且除非目录已经为空,否则它不会删除目录。在缺少该选项或它不够用时,可用 -exec 对匹配项调用 rm:
find /var/log/app -type f -name '*.log' -exec rm {} +
末尾的 + 会收集匹配到的文件,分批传给 rm,而不是为每一个文件都启动一个新进程,在大型目录树上速度明显更快。把 + 换成 \; 则会每个文件启动一次 rm,只有当命令必须逐个处理文件时才需要这样做。
更安全的删除选项
rm -i 会对每个文件逐一提示,虽然彻底,但在文件稍多时就很快让人厌倦。-I 选项是折中之道:它只在删除超过三个文件或递归删除时提示一次。
rm -I *.log
rm: remove 12 arguments?
这一条提示会告诉你通配符展开成了多少个文件,而这正是通配符删除前你想看到的数字。同样的行为也能通过 --interactive=once 启用;此外 --interactive=always 对应 -i 的逐文件提示,--interactive=never 则用于抑制所有提示。
当你清理的目录树中可能包含挂载点时,加上 --one-file-system。递归删除时,rm 会跳过任何与你传入路径不在同一文件系统上的目录,从而避免误删蔓延到挂载的备份盘或网络共享:
rm -rf --one-file-system /mnt/staging
GNU rm 默认拒绝递归操作 /,这就是默认启用的 --preserve-root 行为。但这个保护比听上去更窄:它保护的是字面路径 /,而不是 rm -rf /*——后者由 shell 把通配符展开为顶层目录列表,rm 自始至终都没看到根参数。
如何删除目录
在 Linux 中,可以使用 rmdir 和 rm 命令删除目录。
rmdir 是一个用于删除空目录的命令行工具;而用 rm,则可以递归地删除目录及其全部内容。
使用 rmdir 命令
rmdir 仅在目录已经为空时才删除它,否则会拒绝。这种「拒绝」正是它的特性:它让你无需先检查内容,就能清空一个你认为已空的目录;而一旦你判断错了,命令会拦住你。
要删除一个空目录,使用 rmdir 命令并跟上目录名作为参数:
rmdir dirname
如果目录不为空,你会看到一条错误信息:
rmdir: failed to remove 'dirname': Directory not empty
要删除一个目录以及它那些同样为空的父目录,加上 -p 选项:
rmdir -p parent/child/grandchild
使用 rm 删除目录
默认情况下,rm 在不带任何选项时无法删除目录。
要用 rm 删除空目录,执行该命令并带上 -d 选项:
rm -d dirname
要删除非空目录及其中的全部文件,使用 rm 并带上 -r(recursive,递归)选项:
rm -r dirname
如果目录或其内部的某个文件是写保护的,系统会提示你确认删除。
要无提示地删除非空目录及其全部文件,使用同时带 -r(递归)和 -f(强制)选项的 rm:
rm -rf dirname
要一次性删除多个目录,使用 rm -r 并跟上以空格分隔的多个目录名:
rm -r dirname1 dirname2 dirname3
与文件一样,你也可以使用通配符模式匹配多个目录。
指向目录的符号链接是这里常见的困惑来源。用 rm link 删除链接本身,不要带末尾斜杠。写成 rm -r link/ 会跟随链接、删除它所指目录的内容。我们关于删除符号链接的指南介绍了更多细节。
改用回收站删除文件
上面介绍的方法都不可逆转。如果你真正想要的是桌面那种行为——删除的文件留在回收站里,直到你清空它——命令行同样可以做到。
在安装了桌面环境的系统上,gio 通常已作为 GLib 的一部分存在:
gio trash filename
文件会被移动到 ~/.local/share/Trash,你的文件管理器会显示它,而 gio trash --restore 可以把它恢复回来。运行 gio trash --empty 则可彻底清空回收站。
trash-cli 是不依赖桌面的选择,在服务器上同样能用。在 Ubuntu、Debian 及其衍生发行版上安装:
sudo apt install trash-cli
在 Fedora、RHEL 及其衍生发行版上:
sudo dnf install trash-cli
该软件包提供了 trash-put 用于删除、trash-list 用于查看回收站中有什么、trash-restore 用于把文件挑出来恢复:
trash-put filename
这两个工具都是移动文件而非复制,因此只能在单一文件系统内工作。位于独立挂载点上的文件会被移到该挂载点的回收站目录,而两者都无法把只读文件系统上的文件移入回收站。
速查表
如需可打印的速查表,请参阅 rm 速查表。
| 命 | 令 |
|---|---|
说 | 明 |
故障排查
「Permission denied」(权限被拒绝):你对存放该文件的目录没有写权限和执行权限,文件自身的权限在此无关紧要。用 ls -ld dirname 检查父目录,如果你拥有它就用 chmod 调整;若需要更高权限,可在命令前加 sudo。
「Operation not permitted」(不允许的操作):与上述提示原因不同。要么父目录设置了粘滞位而文件属于他人,要么文件被设为不可变。用 lsattr filename 检查,若输出中出现 i,则用 sudo chattr -i filename 清除该属性。
「Directory not empty」(目录非空):使用 rmdir 时出现,因为 rmdir 只删除空目录。要删除目录及其内部所有内容,请使用 rm -r dirname。
「Is a directory」(是一个目录):使用通配符删除时出现,因为 rm dirname/* 会连子目录一起匹配,而 rm 若不加 -r 就会跳过它们并报此错。用 rm -r dirname/* 可将子目录一并删除;若只想删文件,可用 find dirname -maxdepth 1 -type f -delete。
用通配符误删文件:用 rm 删除的文件不会进入回收站,也难以恢复。运行 rm *.ext 之前,先用 ls *.ext 预览将匹配哪些文件。对于关键操作,使用 rm -I 确认展开后的数量,或通过 trash-put 删除,使文件仍可恢复。
以短横线开头的文件无法删除:如果文件名以短横线开头,rm 会把它当作选项。可用 rm -- -filename 或 rm ./-filename 来解决。
「Argument list too long」(参数列表过长):通配符展开出的文件数超过了 shell 一次命令能传递的上限。改用 find . -maxdepth 1 -type f -name '*.log' -delete,这样 shell 永远不会构造出超长的参数列表。-delete 会直接删除每个匹配项,而需要调用 rm 时,-exec rm {} + 会分批处理匹配项。
常见问题(FAQ)
rm 和 unlink 有什么区别?两者都能删除文件。rm 接受一个或多个文件操作数,并支持递归、提示、强制删除等选项;unlink 只接受恰好一个文件操作数,没有任何删除选项。两个命令都不会解析通配符——shell 会在命令运行前替你展开。
用 rm 删除的文件能恢复吗?不容易。rm 不会把文件移到回收站文件夹,而是移除其目录项并把磁盘块标记为空闲。若数据块尚未被覆盖,借助取证工具或许还有可能恢复,但无法保证。若打算尝试恢复,应立即停止对该文件系统的写入。
如何删除超过 30 天的文件?使用带 -mtime 测试的 find:find /path -type f -mtime +30 -delete。由于 find 会把文件年龄向下取整,这会在经过 31 个完整天数后才开始匹配。若想让文件一满 30 天就匹配,可用 -mtime +29;并且务必先不带 -delete 运行一次以查看列表。
何时该用 shred 而不是 rm?仅当文件系统和存储设备确实原地覆写数据时,才使用 shred -u。在采用 data=ordered 或 data=writeback 模式的 ext3、ext4 文件系统、且存储介质为常规机械磁盘时,它可能有效。不要依赖它处理 SSD、会记录文件数据日志或采用写时复制的文件系统、RAID、快照或备份。对于整块设备,应改用加密或硬盘的安全擦除。
rm -rf 危险吗?是的。rm -rf 会立即、且不经过确认地删除目标路径下的所有内容。绝不要用 /、~ 或可能为空的变量作为参数来运行它。加上 -I 可在不放弃递归的同时恢复一次确认提示。
如何在删除目录本身的同时清空其中的所有文件?使用 rm -r dirname/* 可在保留目录的同时删除其内容。注意 * 不会匹配隐藏文件,因此以点开头的条目会保留下来。要把它们也一并删除,可使用 find dirname -mindepth 1 -delete。
结束语
rm 命令是 Linux 中删除文件和目录的主要工具。当你只想安全地删除空目录时用 rmdir,删除单个文件时用 unlink,按时间或模式而非名称来筛选文件时用 find,而文件内容比文件本身更重要时用 shred。当你在「出错代价高昂」的环境工作时,rm -I 只需多敲一次键,却会告诉你即将丢失多少个文件。关于 rm 选项与标志的完整参考,请参阅 rm 命令指南。