'rm .*' 会删除父目录吗?

ter*_*don 58 shell posix wildcards rm

该表达式.*由 bash 扩展以包括当前和父目录:

$ ls -la
total 2600
drwxrwxrwx   2 terdon terdon 2162688 Sep 10 16:22 .
drwxr-xr-x 142 terdon terdon  491520 Sep 10 15:34 ..
-rw-r--r--   1 terdon terdon       0 Sep 10 16:22 foo
$ echo .*
. ..
Run Code Online (Sandbox Code Playgroud)

如果我rm -rf .*使用 GNU bash 在我的 Debian 上运行,version 4.2.36(1)-release并且rmrm (GNU coreutils) 8.13,我会收到以下消息:

$ rm -rf .*
rm: cannot remove directory: `.'
rm: cannot remove directory: `..'
Run Code Online (Sandbox Code Playgroud)

这是 GNU 的东西还是 POSIX?是否有任何 *nix 系统可以让上述命令静默删除...

另外,这是外壳程序还是rm命令本身的安全功能?

Sté*_*las 63

在POSIX规范的最新(2017年)版的rm效用是在这里(和前一个),禁止删除...

如果文件 dot 或 dot-dot 中的任何一个被指定为操作数的基本名称部分(即最终的路径名组件),或者如果操作数解析为根目录,则 rm 应将诊断消息写入标准错误并且不执行任何操作更多这样的操作数。

正如@jlliagre 所指出的,关于部分/是 SUSv4 中的一个补充。

我能找到的最古老的公开可用的 Unix 规范(XPF4 CAE rev2 (1994))已经指定.并且..不能被删除,尽管 GNU fileutils 更改日志中的评论表明它已经出现在旧的 POSIX 规范中。

请注意,它也适用于dir/..../,但某些实现(包括 UNIX 认证的,如 Solaris 11 和 macOS)仍然无法防止rm -rf ../rm -rf .*/)。

历史

早期的 unice

-r要选择rm在Unix的V3(1973)加入虽然它只是删除目录的内容,你仍旧需要使用rmdir,删除目录。

这在 Unix V7(1979 年,该版本也引入了 Bourne shell 并且大多数 Unices 从中派生而来)中发生了变化。rm -r现在也删除了目录,并且不会删除..目录树。该手册页指出:

禁止删除文件..只是为了避免无意中做类似的事情的反社会后果rm -r .*

(尽管有人可能会争辩说这rm -r .*仍然是反社会的,因为它删除了所有内容,因为它.被包含在内)。

.尽管它不会取消链接...条目,但它仍然接受删除。那么,rm -r .是清空当前目录的有效方法。

另请注意,保护措施仅适用于文字..参数,而不适用于dir/.../..。因此,rm -rf ./.*仍然会递归删除父目录中的所有内容。

有趣的是,这已经解决了 globs 可能包含的错误/错误功能.以及..它们的扩展。这在 80 年代后期zsh(1990) 和fish(2005)的 Forsyth shell(原始 Minix shell 和 pdksh 的基础)中得到了修复,但在其他 shell 中没有修复,特别是在 POSIXsh语言中需要扩展.*以包含...if它们由readdir()(bash部分地解决了问题,shopt -s dotglob其中 globs (除了.xxx那些) 不包含.or ..,并且使用ksh,您可以通过执行来修复它FIGNORE='@(.|..)')。

何时.添加完全禁止并不总是很清楚,并且随着每个 Unix 的不同而不同。下面的一些发现。

BSD

禁止.在 2.9BSD (1983) 和 2.10BSD (1987) 之间以及 4.2BSD (1983) 和 4.3BSD (1986) 之间添加(请参阅unix-history-repo 中时间戳为 1985 的更改)。

$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.9BSD/root.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `..'
$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.10bsd.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `.' or `..'
rm: cannot remove `.' or `..'\n");
Run Code Online (Sandbox Code Playgroud)

对于dir/.dir/..,请参阅1988 年的此更改(BSD 4.3 Net/1)。

为了这一天,在rmFreeBSD的(和喜欢的MacOS衍生产品)仍然在清空当前或父目录rm -rf ./rm -rf ../虽然(事项rm -rf .*/)。

系统五

我没有太多信息,因为 V7 之后的 AT&T Unix 衍生产品的源代码或二进制文件都没有公开可用。在其在线手册中,HPUX(基于 System III)仍然提到它只禁止,..而实际上它禁止两者,这表明可能至少 SysIII 没有禁止删除.编辑:现在查看SysIIIrm源代码,它是自 Unix V7 以来几乎没有变化)。

我检查过的所有其他在线手册都提到删除.或被..禁止,这应该是符合 POSIX 的。

的Solarisrm时仍然清空当前或父目录rm -rf ./rm -rf ../

GNU

GNU fileutils早期变更日志包含所有历史信息。

虽然最初没有删除...被禁止,..首先,然后两者(包括禁止dir/.),所有1990和1991之间。

其他

正如我们所见,在 中zsh.*(或任何 glob)的扩展从不包括.or ..(即使在sh仿真模式下)。因此,rm内置zmodload zsh/files函数(如果您获得)则不会处理...特别处理。因此,使用该zsh内置函数,您可以rm -rf .orrm -rf ..清空.or ..,但rm -rf .*不会删除.or ..

在 busybox 中rm,在 0.52 (2001) 中添加了禁止删除...

  • @Kevin 并非所有系统都符合 POSIX 标准,并且仅在最新的 POSIX 版本中明确添加了根目录限制。 (6认同)
  • @Stephane:你是对的,但我仍然会在你的答案开头加上一个大大的“是的,它可能会发生!但是......”,所以人们无疑知道确实,在某些(较旧的或只是非-POSIX 兼容)系统,他们可以删除父目录。我试图总是指出这些可能性(即,我尽量保持安全,即使它有时会使答案更难阅读/记住)^^ (2认同)