Python os.path.isdir returns 点为真

Python os.path.isdir returns true for dots

我正在 python 中编写自己的 shell。现在我正在尝试对我的 shell.

执行 cd 命令

执行这个命令的函数有几个变量:

self.current_dir = "C:\" - 默认值,它的变化取决于用户使用 cd 命令的输入

dir = "..." - 用户键入的请求目录。 “...”是导致问题的输入示例。

这是我的代码:

def command_cd(self, dir):
    if os.path.isdir(self.shell.current_dir + dir):
        self.shell.current_dir = self.shell.current_dir + dir + "\"

问题是,由于某些奇怪的原因,当用户键入点时,os.path.isdir(self.shell.current_dir + dir) returns True(就像我上面给出的变量的示例输入一样)。

即使更改点数(甚至超过 5 个点)也会出现问题,我真的不知道是什么原因造成的。

显然没有名为 ... 或类似名称的文件夹。

如果我的问题不够清楚请评论我会编辑它

这是因为现代计算机目录结构中的.指向当前目录。同样,..指向当前目录的父目录。因此,您可以通过在 windows cmd 中键入 cd ..\..\ 来在目录结构中向上导航两个文件夹。这不是一个错误,这是一个功能!我现在无法访问 Windows 机器,但是 cd ... returns 我的 Ubuntu 17.10 笔记本电脑上的错误 bash: cd: ...: No such file or directory。对于大于 2 的任意数量的点,我都会得到相同的错误。如果 python returns True 对于 ...,这是一个错误。我会在你的 cd 命令中添加一些子句,不允许输入超过 2 个点,或者让 4 个点进入 2 个目录,6 个点进入 3 个目录等等。

.是当前目录,..是父目录,没有大于两个点的引用。

但是,之所以os.path.isdir() returns为真,是因为python把大于两个点的都记为一个点。

import os

print(os.path.abspath(".......") == os.path.abspath("."))
print(os.path.abspath("....") == os.path.abspath("."))

# and that
print(os.path.samefile('......', '.'))
# also prints True

它们都会打印 True,因为 ............ 指向同一个地方。


正如 chepner 在评论中指出的那样,这个问题不会出现在 POSIX 系统中,而是由 os.stat 错误地将 '....' 等同于 '.' 引起的(事实并非如此,请参阅稍后编辑)


重要编辑:

eriksun 评论:

Windows os.path.isdir is implemented by calling GetFileAttributes, which calls NtQueryAttributesFile. Like all file system functions, first it has to convert the DOS path to a native NT path. To the kernel "." and ".." are just normal names, so the runtime library first has to normalize the path via the function RtlGetFullPathName_Ustr, which also gets used by os.path.abspath, so the result is similar. The way it reduces more than two dots and trailing spaces in the final component is a legacy inherited from DOS. It's doing its best to emulate an OS from the 1980s.

因此此问题与python本身无关,因为此问题也发生在Windows cmd,cd c:\.....cd .\....\.. Windows通过用一个点引用两个而不是两个点,仍然会让你摆脱它。因为它是从 DOS 继承来的,将两个以上的点减少为一个并删除尾随空格。