在摆弄文件系统时,我尝试了以下操作:
mkdir a
cd a
rmdir .
其结果是:
rmdir: failed to remove ‘.’: Invalid argument
好吧,先生rmdir
,让我比你聪明一点:
rmdir ../a
...好的。
什么?这次没有错误?
我的终端仍然显示我在目录中a
,但未ls -a
列出任何内容(也.
没有..
),但ls ..
仍可pwd
按预期工作。
我是不是就像那些卡通人物一样,自己砍断了树枝却还没有倒下?
如果我尝试
mkdir ../a
它创建了一个目录a
,但这仍然不是我所在的目录(ls -a .
并ls -a ../a
显示不同的结果)。
如果我尝试使用它创建一个文件,touch b
则会回复:
touch: cannot touch ‘b’: No such file or directory
但touch .
有效。
最后,一旦我离开我的目录,它就会消失并且我无法返回它。
编辑:有人能解释一下这里发生了什么吗?这种情况有名字吗?这是文件系统和 Bash 之间的问题,还是 Bash 中的一些特殊硬编码行为?
答案1
这与 bash 无关。
这是几十年前 Unix 的标准行为。这是内核的标准行为,与 shell 无关。
需要记住的重要一点是文件和目录不必有名称。只要 (a) 链接数不为零、(b) 由打开的文件描述符引用,或 (c) 是进程的工作目录,文件或目录就会一直存在。(还有其他几个条件可以防止文件或目录消失,但它们与您的问题无关。)
对于文件,您应该习惯于创建一个未命名的临时文件,当最后一个打开的文件描述符关闭时,该文件会自动清除,方法是打开一个文件然后取消链接,以便其链接计数降至零。 (这掩盖了许多与这个问题无关的安全相关细节。)
你也应该习惯于这样的想法:你可以取消链接某个进程具有打开的文件描述符的文件,创建一个同名的新文件,然后它们将被两个不同的文件。
你只是对目录做了同样的事情。你清空了目录并取消了链接,但它继续存在,直到它不再被打开的文件描述符引用,也不再是任何进程的工作目录。当你用你取消链接的同名名称创建一个新目录时,你就两个不同的目录。
请注意,如果命名的目录是任何进程的当前目录,SUS 可能rmdir ../a
会失败。(这并不是像某些人认为的那样,给 Windows NT 上的 POSIX API 提供漏洞。例如,QNX 在这种情况下也会调用失败。)您显然正在运行一个操作系统(在没有考虑根目录和挂载点的情况下,您的问题不涉及这些因素)选择另一个允许的替代方案,即取消链接目录,删除.
和..
条目,并禁止创建新条目。
进一步阅读
答案2
作为 JdeBP 优秀产品的补充回答,你可以通过检查相关目录的 inode 来确认确实发生了这种情况:
$ mkdir ~/foo
$ ls -di ~/foo
16654483 /home/terdon/foo
$ cd ~/foo
$ rmdir ../foo/
$ ls -di ../foo
ls: cannot access ../foo: No such file or directory
$ mkdir ../foo
$ ls -di ../foo
16654484 ../foo
请注意,inode 编号已更改,这是一个新目录,除了恰好具有相同的名称之外,与旧目录没有任何关联。