为什么 Windows 上的 cmd.exe shell 在使用斜杠('/') 作为路径分隔符时会失败?

22

就在我认为我已经见识过所有的Windows路径问题时,我现在遇到了一个只有在使用“/”(正斜杠)作为路径分隔符时才会失败的情况:

C:\temp\tcbugs>mkdir "dir1 with spaces"

C:\temp\tcbugs>echo hi > "dir1 with spaces"\foo.txt

C:\temp\tcbugs>type "dir1 with spaces\foo.txt"
hi

C:\temp\tcbugs>type "dir1 with spaces/foo.txt"
The system cannot find the file specified.

这个问题特别有趣的地方在于它似乎只存在于cmd.exe shell中,而在PowerShell(以及可能的win32 API)中并不存在:

PS C:\temp\tcbugs> type 'dir1 with spaces/foo.txt'
hi

另一个值得注意的地方是,使用“cd”更改目录并在cmd.exe中使用“/”作为路径分隔符确实有效:

C:\temp\tcbugs>mkdir dir2_no_spaces

C:\temp\tcbugs>cd ./dir2_no_spaces

C:\temp\tcbugs\dir2_no_spaces>cd ..

然而,我无法在任何在线资料或MSDN的常被引用文档中找到关于这个特定问题的参考:

文件名、路径和命名空间

这让我想问:为什么会出现这种情况,是否有明确的来源记录了这种怪异行为?

更新:

dbenham指出,在目录名称中是否包含空格的情况下都存在这个问题,因此删除了标题和问题正文中对它的引用。还添加了一个可以工作的'cd ./'示例,而其他命令则无法工作。


9
在API层面上,/可以用作路径分隔符,但是您不是直接调用API。您正在使用cmd.exe,而cmd.exe将/解析为命令行选项。 - Raymond Chen
我早有所料,但也期望有关此情况的文档会被特别记录在某个地方。我找到的覆盖路径分隔符的文档——即使是在cmd shell的上下文中——似乎都没有提到这个特定问题。 - Garen
1
有没有文档说明在cmd.exe中斜杠可以用作路径分隔符? - Raymond Chen
@BrianNixon:似乎CD在处理以/分隔的路径时表现不一致。如果路径/开头,CD会说找不到它(除非你尝试使用/D,这种情况下它会抱怨语法错误)。 - Andriy M
http://webpages.charter.net/danrollins/techhelp/0295.HTM - Cheers and hth. - Alf
显示剩余7条评论
3个回答

10

经编辑,移除了意见

无论Windows CMD.EXE是否应该支持路径中的正斜杠,事实上有时它能正常工作,有时不行,有时看起来可以工作但会给出错误结果,也就是说这是一个 bug。

现在是进行一些实验的时候啦 :-)

所有测试均在 Vista 上运行。

C:\>md "c:/temp/"

C:\>REM The forward slash works with MD!

C:\>echo hello world 1>>"c:/temp/test.txt"

C:\>REM Redirection works with forward slashes!

C:\>type "c:\temp\test.txt"
hello world

C:\>REM Of course TYPE works with back slashes

C:\>type "c:/temp/test.txt"
The system cannot find the file specified.

C:\>REM But forward slash version fails

C:\>type "c:/temp\test.txt"
hello world

C:\>REM But TYPE works with forward slash as long as last slash is back slash

C:\>dir "c:/temp/test.txt"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp

File Not Found

C:\>REM Note how DIR lists the directory with a \, yet fails to find any files

C:\>dir "c:/temp/*"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp

File Not Found

C:\>REM DIR Still fails with forward slashes

C:\>dir "c:/temp/"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp

05/09/2012  09:58 PM    <DIR>          .
05/09/2012  09:58 PM    <DIR>          ..
05/09/2012  09:58 PM                13 test.txt
               1 File(s)             13 bytes
               2 Dir(s)  337,001,615,360 bytes free

C:\>REM But forward slash works if no file is specified!

C:\>dir "c:/temp\test.txt"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp

05/09/2012  09:58 PM                13 test.txt
               1 File(s)             13 bytes
               0 Dir(s)  337,001,615,360 bytes free

C:\>REM And DIR works with forward slash as long as last slash is back slash


C:\>REM Now add another folder to the path hierarchy

C:\>md "c:/temp/temp/"

C:\>REM Still can create folder using forward slashes

C:\>copy "c:/temp/test.txt" "c:/temp/temp/"
The system cannot find the file specified.
        0 file(s) copied.

C:\>REM Failed to copy with forward slashes

C:\>copy "c:/temp\test.txt" "c:/temp/temp/"
        1 file(s) copied.

C:\>REM But forward slash works if last slash before file name is back slash


C:\>REM Rerun some past tests

C:\>type "c:/temp/test.txt"
The system cannot find the file specified.

C:\>REM Good - it still fails

C:\>dir "c:/temp/test.txt"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp

05/09/2012  09:58 PM                13 test.txt
               1 File(s)             13 bytes
               0 Dir(s)  337,001,615,360 bytes free

C:\>REM What is going on?! :( Why did that seem to work now?
C:\>REM More on that later.


C:\>REM Now test the new folder

C:\>type "c:/temp/temp/test.txt"
The system cannot find the file specified.

C:\>REM Forward slashes still fail with TYPE

C:\>type "c:/temp/temp\test.txt"
hello world

C:\>REM But forward slash still works as long as last slash is back slash

C:\>dir "c:/temp/temp/*"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp\temp

File Not Found

C:\>REM Again, forward slashes fail, but directory path is listed properly

C:\>dir "c:/temp/temp/"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp\temp

05/09/2012  09:58 PM    <DIR>          .
05/09/2012  09:58 PM    <DIR>          ..
05/09/2012  09:58 PM                13 test.txt
               1 File(s)             13 bytes
               2 Dir(s)  337,001,615,360 bytes free

C:\>REM And again it works if no file is specified

C:\>dir "c:/temp/temp\test.txt"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp\temp

05/09/2012  09:58 PM                13 test.txt
               1 File(s)             13 bytes
               0 Dir(s)  337,001,615,360 bytes free

C:\>REM Again forward slashes work as long as last slash is back slash

这里有一个清楚地展示了一个 bug 的案例。
c:\>dir /s /a-d temp
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp

05/10/2012  08:01 AM                13 test.txt
               1 File(s)             13 bytes

 Directory of c:\temp\temp

05/10/2012  07:57 AM                10 test.txt
               1 File(s)             10 bytes

     Total Files Listed:
               2 File(s)             23 bytes
               0 Dir(s)  337,325,191,168 bytes free

c:\>REM Note the different file sizes found in each directory

c:\>dir "c:/temp/test.txt"
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of c:\temp

05/10/2012  07:57 AM                10 test.txt
               1 File(s)             10 bytes
               0 Dir(s)  337,325,191,168 bytes free

c:\>REM It is listing the wrong file!

有人可能会争论Windows命令提示符是否“应该”支持正斜杠。但是最后的结果是错误的!即使在使用正斜杠时存在运算符错误,Windows也不应该给出该结果。


3
你称某个行为为“bug”的依据是什么?(正如Raymond Chen所问的,哪里有文件说明cmd应该接受斜杠作为路径分隔符?)而且,正如Larry Osterman所指出的那样,使用斜杠作为选项分隔符的起源甚至可能不是微软的做法。你会将不能处理以“-”开头的文件名的Unix传统命令的行为描述为“bug”吗? - Brian Nixon
8
我认为,如果系统的结果不一致,那么这就是一个漏洞(或设计缺陷)。如果CMD在路径中使用正斜杠时可以工作,或者不使用正斜杠也可以工作,我会非常满意,但有时可以工作,有时不行,这在我的看法中是一个漏洞。而我在编辑后答案中的最后一个示例明显展示了任何理性定义下的“漏洞”。我已经从答案中删除了个人观点,并坚持事实。但在这个评论中,我要说:“我相信微软试图支持路径中的正斜杠,结果得到了一个有缺陷的未记录功能”。 - dbenham
2
@dbenham:我几乎可以确定微软没有尝试在cmd中支持正斜杠。他们(有意地)在API中支持它们,但在cmd中,当文本只是传递给API而不是解析时,它恰好可以工作。内置命令mdtype之间的区别确实很奇怪。 - Jan Hudec
@JanHudec - 我想 cmd 的开发者可能对 API 对 / 的解释有点幼稚,但我不太相信。无论哪种情况,他们都应该知道并进行相应设计。在所有内部命令情况下支持/作为路径分隔符或在所有情况下禁用它应该是一个有意识的决定。这是我的意见。 :-) 或者至少记录“/”作为路径分隔符不可靠,因此应避免使用。 - dbenham
@dbenham:它应该已经被记录了。也许它确实有记录,但是微软的文档很难找到你真正感兴趣的内容。它不可能得到支持,因为cmd.execommand.com的NT端口,我不知道在那个时候是否支持正斜杠(DOS不符合POSIX标准,只有WinNT及更高版本才支持)。 - Jan Hudec

-1

我们在斜杠方面遇到了一些奇怪的行为,追踪发现,带有前导斜杠的路径并不被视为绝对路径,因此

C:\>cd /temp

C:\temp>rem works we are in the root directory

C:\temp>cd /temp
Das System kann den angegebenen Pfad nicht finden.

C:\temp>rem does't work but

C:\temp>cd \temp

C:\temp>rem \ indicates absolute path

C:\temp>cd ..

C:\>cd /temp

C:\temp> cd /ca

C:\temp\CA>rem qed

也许这也解释了上面提到的错误 - 我不清楚命令在哪个目录下执行。

不错的理论,但在我的Windows 7机器上却表现出不同的行为。 cd /temp 对我来说很好,将其视为根文件夹。 但我在帖子中列出的其他漏洞仍然适用。 - dbenham
这些是有趣的例子,但它们甚至没有开始回答“为什么”的问题。 - Bryan Oakley

-7

我不确定为什么在PS中'/'可以工作。回到历史上,DOS是基于UNIX的一个小型UNIX版本。在UNIX中,路径分隔符是'/',而在DOS中则是'\'。我之前曾经开发过一些Windows和DOS应用程序。为了将一些UNIX模式(如命令或路径)转换为有效的DOS命令或路径,并确保它们是有效的,我编写了一个小型转换器来将'/'转换为'\',就像这样:

string fileNameFromWeb;
...
string windowsFile = fileNameFromWeb.repleace("/", @"\");

如果您需要在访问Windows文件时允许使用'/'符号,可以将此功能添加到您的应用程序中。我猜测PS可能会有这种类型转换器,允许命令或路径使用'/'或'\',或者Windows会在文件名中接受'/'。


谢谢,但最初导致我遇到这个问题的是一些第三方软件中的错误 - 所以这个选项对我不可用。当然,如果这是我的软件,我会简单地做出类似的操作,而不必问这个问题。 - Garen
如果您正在使用.NET或Mono,可以使用Path.DirectorySeparator而不是硬编码它。http://msdn.microsoft.com/en-us/library/system.io.path.directoryseparatorchar.aspx - dwerner
8
抱歉,但“DOS基于UNIX,并且是UNIX的一个小子集。” 这句话可能是最大的亵渎之一!实际上,DOS在某种程度上是基于CP/M的。 - Christian.K
它在PS中可以工作,因为它的解析规则不同,当字符串未经修改传递给API时,它可以正常工作。 - Jan Hudec
@dwerner:如果你使用的是.NET或Mono,或者C++或其他任何语言,你总是可以使用“/”。cmd.exe是Windows中唯一一个(至少我从未听说过其他的)无法使用正斜杠的部分。 - Jan Hudec
@JanHudec:当然,有相当数量的工具允许前导“/”引入命令行选项。值得庆幸的是,对于我们使用bash的人来说,大多数这些工具也允许“-”。(无论你在Windows上使用哪个bash,以“/”开头的参数往往会在调用它不认识的程序时受到路径转换的影响,因此通常更容易使用“-”引入选项而不是与路径转换作斗争。)你可能只是指非前导“/”? - SamB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接