为什么“ cd ..”在Windows命令行中有效?


86

当键入cd..之间没有空格时cd..Windows命令提示符将愉快地切换到父文件夹。有这种行为的解释吗?该命令不遵循以下格式command<space>arguments

工作,但不应该吗?

此外,为什么这不能产生一致的结果?

回声..


24
您的问题的前提似乎已被打破。您可以提供任何证据证明这种说法在语法上是不正确的吗?
Lightness Races in Orbit

13
我认为“ command <space> arguments”从来不是cmd(或其任何前身)的标准格式;考虑例如dir/a或类似的VMS语法。
grawity

6
cd非常特别。您可以输入cd c:\program files不带引号的
格式

20
这是一篇非常有趣的文章,解释了Windows Shell逻辑的怪癖,以及它可能引起的混乱:thedailywtf.com/articles/The-Core-Launcher
vsz 2013年

3
为什么cd..起作用?因为Microsoft遇到了使其明确工作的麻烦。cd是Windows命令解释器中内置的命令,Microsoft可以使他们的解释器执行所需的任何操作。(作为另一个示例,cd也不需要引用名称中带有空格的目录。)
jamesdlin

Answers:


106

正如其他一些答案/评论所指出的那样,命令后必须有空格的想法是不正确的。一个著名的示例是,您可以在命令后键入正斜杠,而无需先使用空格。

但是,还有另一种行为,它的含义不太清楚,并且允许cd..您询问“ ”。此行为还允许“ cd\”正常工作。

您描述的行为对于命令行解释器内部的所有命令都是一致的。如果您有某些符号,包括句点,正斜杠或反斜杠,则将检查前面的字符以查看它们是否是“命令行解释器”外壳程序(CMD.EXE或其前身COMMAND.COM)内部的命令。 )。

这可以在检查单词是否指向文件或子目录之前完成。该cd命令是正确的。可悲的是,在制作样本时,我发现该copy命令不会发生这种情况,因此结果不一致:它们不一定与所有内部命令都相同。我没有继续搜索以比较(很多)其他命令行deldir,因此,我只是建议您在尝试依赖没有空格的情况时要格外小心。

现在,该问题还询问了echo命令:这是一个不寻常的例外,因为我认为这echo.是DOS专家众所周知的。这可能已记录在案。至少在Win7的CMD中,这种行为是,如果命令以“ echo.” 开头,则第一个句点将被忽略。因此,“ echo..hi”变成“ ”的输出.hi。原因是echo.可以使用“ ”来打印空白行。相反,在Unix中,您可以通过单独运行“ echo”命令来简单地做到这一点。但是,在DOS中,单独运行“ echo”命令将输出当前的“ echo ”设置。同样,DOS对待“ Echo *Off*”和“Echo *On*”作为更改当前回显设置的特殊值。如果您实际上要打印单词“ Off”,那么“ Echo.Off”就可以解决问题(至少使用最近版本的Microsoft CMD命令行解释器。)

因此,至少该echo命令具有半合理的解释。至于其余的命令,我曾经认为内部命令具有优先权。但是,当我尝试进行一些测试时,我发现实际上并不一致。我将通过此处记录的一些示例对此进行演示。


这里有些例子。我确实使用了提升的命令提示符,因此UAC不会为我写根目录而烦恼。这是通过Microsoft Windows 7的CMD.EXE完成的。我怀疑行为可能与其他版本不同,例如旧MS-DOS版本的COMMAND.COM或其他公司发布的软件(DR-DOS的COMMAND.COM)。

(这个答案已经相当长了,所以我没有包括清理我在文件系统上弄得一团糟的命令。有一点清理工作,但是清理不多。)

这是一个证明内部命令创建优先级的示例。(我还演示了使用双冒号有效地作为注释的鲜为人知的功能,该功能在批处理文件中也很好用。从技术上讲,在批处理文件中,它被处理为GOTO无法到达的标签,然后结束比REM命令快。)

C:\东西> MD CD
C:\东西> 回声回声子目录 >> CD \ a.bat
C:\东西> MD \一个
C:\东西> \ CD \ a.bat。
子目录

C:\东西> ::从子目录
C:\ something> cd \ a
C:\ a> ::更改了当前目录,因此cd优先

更新:经过进一步的试验,我发现如果指定的目录不包含句点,则内部cd命令仅优先于文件系统。因此,如果您有一个名为“ a.bat ” 的目录,则可以运行“ **cd\a.bat**” ,然后将运行批处理文件。

这种对较不常见行为的探索(因为大多数目录中可能没有句点)使我更新了自己的发现。事实证明,cd命令实际上比我最初认为的更类似于copy命令。

尽管我最初认为cdcopy命令的行为有所不同,但现在我发现这是由于我提供的名称模式。不过,我回顾了我的较早结果,并确定了我较早记录的测试确实有助于显示在名称中包含句点和扩展名以及何时不包含时发生的一些区别。因此,我仍将下面的较早发现包括在内(大部分内容未发生变化,但有一些非常小的更新,因此我所说的是正确的)。

这是一个示例,演示具有完整路径的copy,当不使用扩展名时,它不使用与cd相同的优先级(优先使用内部命令):

C:\ something> echo echo root >> \ try.bat
C:\ something> md copy
C:\ something> echo echo子目录>> copy \ try.bat
C:\ something> 。\ copy \ try.bat从子目录
子目录

C:\东西> 复制\ try.bat
子目录

C:\东西> ::咦?为什么不覆盖并从根目录运行?
C:\ something> ::显然,内部复制命令没有检查子目录和完整文件名的优先级(即使内部cd命令在目录没有扩展名的情况下也具有优先级)
C:\ something> ::
C:\某物>::另一个测试:我可以在
C:\ something> ..copy .. \ try.bat
子目录

C:\ something> 的末尾添加无用的句点::: 好的,太好了。但这将不会检查子目录:
C:\ something> copy .. \ try.bat已复制
        1个文件。

C:\ something> ::运行了内部复制命令

我的早期发现表明,这些结果表明命令行外壳程序具有优先权:

  • 在内部命令名称后立即指定反斜杠时,将其复制到文件系统(而不是内部复制命令)
  • 在内部命令名称后立即指定反斜杠时,请转到内部cd命令(而不是文件系统)。
  • 在内部命令名称之后指定一个句点时,将其复制到内部复制命令(而不是文件系统)。

这清楚地表明,复制命令(带有扩展名的完整文件名)和cd命令(不带扩展名作为目录名的一部分)之间的行为不一致。当使用反斜杠时,copy命令(具有完整的文件扩展名)将首先检查文件系统,而cd命令则不会(如果目录不包含扩展名)。

(更新:起初,我认为不一致是基于程序之间的不同行为。后来,我发现不一致的确存在,但更多是由所提供的参数引起的。)

实际上,即使这些要点也不是完全准确的,即使我似乎只是证明了我刚才说的每件事。问题是,项目符号点列表不够精确,无法完全准确。(我留下的东西不够精确,因此可以相对容易地比较和区分这些要点。)

但是,为了更加准确,第一个要点应指出命令行外壳程序具有优先级:

  • 到文件系统(而不是内部复制命令)指定当反斜杠,然后将完整的路径的剩余部分,右后的内部命令的名称

以下内容将说明我为何要做出这种区分:

C:\ elsewhere> 此行所需的 echo UAC高程 >> \ needext
C:\ elsewhere> 此行所需的 echo UAC高程 >> \ needext.bat
C:\ elsewhere> md。\ copy
C:\ elsewhere> echo @回波子目录 >>拷贝\ needext.bat
C:\别处> \复制\ needext
子目录

C:\别处> 复制\ needext.bat
子目录

C:\别处> 拷贝\ needext
        1复制的文件(多个)。

C:\ elsewhere> ::下一行还需要UAC
C:\ elsewhere> del \ needext
C:\ elsewhere> del \ needext.bat

(请注意,由于使用了内部复制命令,因此最后一个复制命令会查找名为\ needext的文件。文件\ needext.bat的创建仅是为了帮助轻松地显示它从未被包含单词copy的命令行使用)

这时,我在使用反斜杠时建立了一些不一致(与copy命令的行为有关)...

接下来,我将演示这些命令之间的某些一致性。(因此,有一致性...嗯...有时。我们可能只有一致性,不一致。)接下来,我将显示的是,使用句点时,cd命令的行为确实类似于copy命令。该复制命令使用的内部命令,也是如此的CD命令。

C:\ something> md。\ yetmore

C:\ something> cd。\ yetmore

C:\ something \ yetmore> md。\ md
C:\ something \ yetmore> echo echo subdir >> md \ test.bat
C:\ something \ yetmore> \ MD \测试。
子目录

C:\东西\ yetmore> MD \测试。

C:\东西\ yetmore> 。MD \测试
子目录或文件\测试已经存在。

C:\ something \ yetmore> ::该错误表明我们运行了内部命令。
C:\ something \ yetmore> md .. \ test
C:\ something \ yetmore> md。\ cd
C:\ something \ yetmore> copy。\ md cd
。\ md \ test.bat已
        复制1个文件。

C:\ something \ yetmore> 。\ cd。\ test
subdir

C:\ something \ yetmore> cd。\ test
C:\ something \ yetmore \ test> ::内部命令只能使用一个句点
C:\ something \ yetmore \测试> CD ..
C:\东西\ yetmore> \ CD .. \测试。
子目录

C:\东西\ yetmore> CD .. \测试
C:\东西\测试> ::内部命令也采取了优先级时,两个时期是用过的

因此,在最初的测试阶段(主要侧重于cdcopy命令)(还有md的一些额外用法和一点del),我们真正拥有文件系统优先级的唯一时间是使用copy命令,然后仅在使用完整路径时,文件系统才具有优先级。

经过后续审查,我发现使用扩展名时cd命令还为文件系统赋予了优先级。至少这意味着内部命令之间的处理更加一致。但是,这也意味着我们根据文件系统对象(文件或目录)的名称获得不同的行为。看来该行为正在使用一些非常非常模糊的内部逻辑。因此,指望这种行为可以在不同的操作系统上运行是我认为不安全的事情。


“您描述的行为对于命令行解释器内部的所有命令都是一致的。” ipconfig例如也可以。
乔纳斯·寇立兹(JonasKöritz)

@JonasKöritz:否。您可以在命令“ IPConfig ” 之后加一个(正斜杠),它将起作用,例如IPCONFIG/ALL。但是,那不是我在说的。“ 您所描述的行为 ”(在您的问题中)是在命令名称后放置句点的行为。如果键入,IPConfig.则会收到有关找不到命令的错误。同样(尽管这与您描述的行为无关),如果键入,IPCONFIG\ALL则可以运行.\IPCONFIG\ALL.BAT我制作的自定义文件。因此/,我们不会将它们视为.“ \”或“ \”
TOOGAM

1
我将接受您的回答,以感谢创建它所付出的努力和研究!
乔纳斯·寇立兹(JonasKöritz)'16

2
@Calchas简单测试-尝试执行copy.execopy.com在cmd中执行。它不起作用-它不是可执行文件。
六安2013年

1
@Luann:关于ipconfig,我不同意你的结论。这个问题是关于在命令行开头键入什么。Windows / DOS通过文件扩展名标识可执行文件,因此,如果没有扩展名,则无法运行名为“ ipconfig”的程序(在Windows中,与Unix允许的不同)。关于下一条评论,我不知道谁是“ Calchas”。(当您指定一个at符号时,通常是在页面其他位置显示的用户的第一个字符。)我同意,运行“ copy.exe”将使用内部copy命令(并通过.exe)。(您可以运行.\copy.exe
TOOGAM

41

您假定命令名称及其参数必须用空格分隔,特别是,但这不是正确的。只要可以明确解释调用,该调用就有效。

在这种情况下,第一个参数以命令名开头,.并且.不能是命令名的一部分,因此,cd..被简单地解析为两个单独的标记。

通常,您的第一个参数将以字母字符开头(例如,路径的开头),因此它将“渗入”到您的命令名中并导致错误……但这不是语法问题。这是一种语义上的。

您可以在使用其他命令时看到相同的效果,包括echo

echo...
..

在这种情况下,我们得到的只有两个时期,因为echo命令本身有一个特殊的规则,这样下:

echo .

或者,扩展为:

echo.

仅输出一个空行。这很方便。显然,它是通过忽略参数中的前导期来实现的。

嘿,这是DOS /批处理。你要理智吗?:D


2
我认为这是因为它是Windows命令行所独有的,例如bash将不允许您这样做cd..
JonasKöritz16

47
@JonasKöritz:那是在完全不同的操作系统上的完全不同的程序。我的自行车也不允许cd..:)
Lightness Race in Orbit

15
@JonasKöritz:alias cd..='cd ..'
mouviciel 2016年

5
@LightnessRacesinOrbit:原来是过滤掉的快捷方式...它出现在所有其他目录的目录并据我所知,从来没有打算赶不止于此。实际上,我认为将隐性建模为文件属性比将其隐式地跟随在文件名之后是一种更简洁的设计。
乔伊(Joey)

4
@joey-我认为更相关的一点不是DOS方法更简单,而是DOS不允许.输入文件名,这意味着它不能成为命令名称的一部分,因此必须已成为参数的一部分。即使DOS像Unix shell一样将命令划分为参数,它仍会.在命令的第一个参数后放置一个a ,因为在命令名中放置无效字符是没有意义的。
Jules

19

cd..命令是正确的,它的定义与原始命令解释器中的定义相同command.com,后来被命名为cmd.exe

命令解释器知道如何处理cd..,因为它.是一个特殊字符,就像\


8
我猜主要问题是该命令不能“在语法上不正确”,因为该语法未在任何地方正式指定,因此,如果主要实现(cmd.exe和/或MS-DOS)接受该命令,则它必须是正确的。
grawity

3
另外,CD不是程序,而是内部命令。与也是内部命令的Echo相似,它不需要空间来工作。echo.效果也一样,它将打印一个空行。
LPChip

2
@Overmind ECHOE不会工作,所以它与CD相同,回声,MD等
LPChip

2
@JonasKöritz,.不会被删除,而只会添加一个空格。md.testmd .test创建目录.test。键入cd.testcd .test将进入目录.test
daniel.neumann

6
@JonasKöritz:因为语法从来都不是命令空间参数。
Lightness Races in Orbit

11

这是向后兼容的黑客。

命令行解释器被设计为与原始MSDOS命令解释器的命令向后兼容,原始MSDOS命令解释器被设计为与CP / M命令解释器向后兼容。CP / M和MSDOS都不允许.在文件名中使用(将其解释为文件名的两个部分,基本名称和扩展名之间的分隔符)。这意味着(至少对于早期版本的DOS),命令解释器可以识别出它是否达到了'。'。(或者文件名中的其他任何非法字符),它通过了命令名的末尾并进入了命令参数。这在DOS和CP / M中都非常常用-例如,这dir/w是一个非常常见的命令,等效dir /w于以水平格式列出文件。

如今,“。” 可以出现在文件名中。这在如何解析命令方面造成了一些麻烦,但是外壳程序仍将.不属于确切文件名的a标识为参数的开头。这在很大程度上是必要的,因为数百万用户已经习惯于键入cd..或包含该批处理文件echo.或任何其他类似命令的批处理文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.