该表达式.*
由 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 .*
. ..
如果我rm -rf .*
使用 GNU bash 在 Debian 上运行,version 4.2.36(1)-release
并且rm
从rm (GNU coreutils) 8.13
,我会收到以下消息:
$ rm -rf .*
rm: cannot remove directory: `.'
rm: cannot remove directory: `..'
这是 GNU 的东西还是 POSIX 的东西?是否有任何 *nix 系统,上面的命令会静默删除.
和..
?
另外,这是 shell 或rm
命令本身的安全功能吗?
答案1
该实用程序的 POSIX 规范的最新版本(截至 2017 年)rm
是这里(还有上一篇那里) 并禁止删除.
和..
。
如果文件 dot 或 dot-dot 被指定为操作数的基名部分(即最终路径名部分),或者如果操作数解析为根目录,则 rm 应将诊断消息写入标准错误并且不执行任何操作更多这样的操作数。
正如 @jlliagre 所指出的,有关的部分/
是 SUSv4 中的新增内容。
我能找到的最古老的公开可用的 Unix 规范(XPF4 CAE 修订版2(1994)),已经指定了这一点.
并且..
无法删除,尽管 GNU fileutils 变更日志中的注释表明旧的 POSIX 规范中已经存在这种情况。
请注意,它也适用于dir/..
和../
,但某些实现(包括 UNIX 认证的实现,如 Solaris 11 和 macOS)仍然无法防范rm -rf ../
或rm -rf .*/
)。
历史
早期的unices
-r
Unix V3 (1973) 中添加了选项,尽管rm
它只是删除目录的内容,但您仍然需要使用rmdir
它来删除目录。
这种情况在 Unix V7(1979 年,该版本还引入了 Bourne shell,大多数 Unices 都源自该版本)中发生了变化。rm -r
现在也删除了目录并且不会删除..
目录树。这手册页状态:
禁止
..
仅仅为了避免无意中做类似的事情而造成反社会后果而删除该文件rm -r .*
。
(尽管有人可能会说这rm -r .*
仍然是反社会的因为它删除了所有内容,因为.
包含在内)。
它仍然接受删除,.
但不会取消链接.
或..
条目。那么,rm -r .
清空当前目录是一个有效的方法。
另请注意,保护措施仅适用于字面..
参数,而不适用于dir/..
or ./..
。因此,rm -rf ./.*
仍然会递归地删除父目录中的所有内容。
有趣的是,这已经解决了 glob 可以在其扩展中包含.
和的错误/错误功能。这个问题在 80 年代末(1990 年)和(2005 年)..
的 Forsyth shell(原始 Minix shell 和 pdksh 的基础)中得到了修复,但其他 shell 没有,特别是 POSIX语言,需要扩展来包含和if它们由(仅解决部分问题,其中 glob(除了那些)不包含or ,并且使用,您可以通过执行来修复它)。zsh
fish
sh
.*
.
..
readdir()
bash
shopt -s dotglob
.xxx
.
..
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");
对于dir/.
和dir/..
,请参阅1988年的这一变化(BSD 4.3 网络/1)。
迄今为止,rm
FreeBSD(以及 macOS 等衍生产品)的 仍然会清空当前目录或父目录rm -rf ./
(rm -rf ../
对于 而言很重要rm -rf .*/
)。
系统V
我没有太多信息,因为 V7 之后的 AT&T Unix 衍生品的源代码或二进制文件均未公开可用。在其在线手册中,HPUX(基于 System III)仍然提到它只禁止,..
但实际上它禁止两者,这表明至少 SysIII 可能没有禁止删除.
(编辑: 现在正在看SysIIIrm
源代码,自 Unix V7 以来几乎没有变化)。
我检查过的所有其他在线手册都提到删除.
或..
禁止,这应该符合 POSIX 标准。
Solaris仍然清空或rm
上的当前目录或父目录。rm -rf ./
rm -rf ../
GNU
这GNU fileutils 的早期变更日志拥有所有历史信息。
虽然最初既不删除.
也不..
禁止,但..
先被禁止,然后两者(包括dir/.
),都在 1990 年至 1991 年间。
其他
正如我们所看到的,在 中zsh
,(或任何 glob)的扩展.*
从不包含.
或..
(即使在sh
模拟模式下)。因此,内置函数rm
(如果你这样做的话,你会得到它zmodload zsh/files
)不会被特殊.
对待..
。因此,使用该zsh
内置函数,您可以rm -rf .
orrm -rf ..
清空.
or ..
,但rm -rf .*
不会删除.
or ..
。
busybox 0.52 (2001) 中增加了rm
禁止删除.
和的功能..