为什么“cd..”在 Windows 命令行中工作?

Jon*_*itz 87 windows command-line command-line-arguments

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

工作但不应该?

另外,为什么这不会产生一致的结果?

回声..

TOO*_*GAM 107

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

但是,还有另一种不太了解的行为,它允许cd..您询问“ ”。这种行为也允许“ cd\”工作。

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

这可以在检查该词是否可以指代文件或子目录之前完成。这对cd命令来说是正确的。可悲的是,在制作示例时,我发现copy命令不会发生这种情况,因此结果不一致:它们不一定与所有内部命令都相同。我没有继续我的搜索来比较(很多)其他命令行deland dir,所以我只是建议如果你试图依赖没有空格发生的事情时要非常小心。

现在,问题还询问了echo命令:这是一个不寻常的例外,因为我认为echo.DOS 专家相当熟悉。这可能被记录在案。至少在 Win7 的CMD 中,行为是如果命令以“ echo.”开头,则忽略第一个句点。于是,“ echo..hi”变成了“ .hi”的输出。这样做的原因是“ echo.”可以用来打印一个空行。相比之下,在 Unix 中,您只需单独运行“ echo”命令即可完成此操作。但是,在 DOS 中,单独运行“ echo”命令将输出当前的“ echo ”设置。类似地,DOS 处理“ Echo *Off*”和“Echo *On*" 作为改变当前回声设置的特殊值。如果你真的想打印单词 " Off",那么 " Echo.Off" 就可以了(至少对于微软的CMD命令行解释器的最新版本来说是这样。)

所以,至少echo命令有一个半合理的解释。至于剩下的命令,我以前认为内部命令有优先权。但是,当我尝试进行一些测试时,我发现这实际上是不一致的。我通过我在此处记录的一些示例来证明这一点。


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

(这个答案已经很长了,所以我没有包括清理我在文件系统上造成的所有混乱的命令。有一点清理,但不多。)

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

C:\something> md cd
C:\something> echo echo subdir >> cd\a.bat
C:\something> md \a
C:\something> .\cd\a.bat
subdir

C:\something> ::从子目录运行的
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 subdirectory >> copy\try.bat
C:\something> .\copy\try.bat 从子目录
子目录

C:\something> copy\try.bat
子目录

C:\something> :: 嗯?为什么不覆盖并从 root 运行?
C:\something> :: 显然,内部复制命令没有优先于检查子目录和完整文件名(即使内部cd命令确实优先,当目录没有扩展名时)
C:\something> ::
C:\某物>:: 另一个测试:我可以在末尾添加无用句点
C:\something> .\copy..\try.bat
子目录

C:\something> :: 好的,太好了。但是这样就不会检查子目录:
C:\something> copy..\try.bat
        1 file(s)复制。

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

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

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

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

(更新:一开始我以为不一致是因为程序之间的行为不同。后来我发现不一致确实存在,但更多是由提供的参数引起的。)

事实上,即使是那些要点也不完全准确,尽管我似乎只是展示了我刚刚说的每一件事。问题是,要点列表不够精确,无法完全准确。(我让事情变得不精确,以便可以相对容易地比较这些要点,并且相对容易地检查。)

但是,更准确地说,第一个要点应该指出命令行 shell 优先:

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

以下将说明我为什么要做出这种区分:

C:\elsewhere>回显此行所需的 UAC 海拔>> \needext
C:\elsewhere>回显此行所需的 UAC 海拔>> \needext.bat
C:\elsewhere> md.\copy
C:\elsewhere> echo @ echo subdir >> copy\needext.bat
C:\elsewhere> .\copy\needext
subdir

C:\elsewhere> copy\needext.bat
subdir

C:\elsewhere> copy\needext
        1 已复制文件。

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

(请注意,最后一个复制命令查找名为\needext的文件,因为使用了内部复制命令。创建文件\needext.bat只是为了帮助轻松表明它从未被包含单词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.\test
subdir

C:\something\yetmore> md.\test

C:\something\yetmore> md.\test
子目录或文件 .\test 已经存在。

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\ test> cd..
C:\something\yetmore> .\cd..\test
subdir

C:\something\yetmore> cd..\test
C:\something\test> :: internal command 也优先考虑两个句点用过的

因此,在主要关注cdcopy命令的初始测试会话期间(还有一些md和一些del 的额外用法),我们真正让文件系统优先的唯一一次是使用copy命令,然后是文件系统仅在使用完整路径时优先。

后来查看后发现cd命令在使用扩展时也给了文件系统优先级。至少这意味着内部命令的处理方式更加一致。然而,这也意味着我们会根据文件系统对象(文件或目录)的名称获得不同的行为。这种行为似乎使用了一些非常非常晦涩的内部逻辑。因此,指望这种行为可以在不同的操作系统上工作,我可能会认为这样做是不安全的

  • @Calchas 简单测试 - 尝试在 cmd 中执行 `copy.exe` 或 `copy.com`。它不起作用 - 它不是可执行文件。 (2认同)

Lig*_*bit 41

您假设命令名称及其参数必须用空格分隔,具体来说,但事实并非如此。只要调用可以被明确解释,调用就是有效的。

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

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

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

echo...
..
Run Code Online (Sandbox Code Playgroud)

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

echo .
Run Code Online (Sandbox Code Playgroud)

或者,通过扩展,这个:

echo.
Run Code Online (Sandbox Code Playgroud)

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

嘿,这是 DOS/Batch。你想要理智吗?:D

  • @JonasKöritz:这是一个完全不同的操作系统上的完全不同的程序。我的自行车也不允许使用 `cd..` :) (47认同)
  • @JonasKöritz:`别名 cd..='cd ..'` (16认同)
  • @LightnessRacesinOrbit:最初它是过滤掉 `.` 和 `..` 的快捷方式,它们在每个其他目录中都显示为目录,据我所知,它从来没有打算捕获更多。实际上,我认为将隐藏性建模为文件属性是一种更简洁的设计,而不是隐式地遵循文件名。 (5认同)
  • @joey - 我认为更相关的一点不是 DOS 方法更简单,而是 *DOS 不允许在文件名中使用 `.`*,这意味着它 * 不能成为命令名称的一部分 * 因此 *一定是争论的一部分*。即使 DOS 像 Unix shell 那样将命令分成参数,它仍然会在命令后放置一个 `.` 到第一个参数中,因为在命令名称中放入无效字符是没有意义的。 (4认同)
  • 我认为这是因为它是 Windows 命令行独有的,例如 bash 不允许你做`cd..` (2认同)
  • @Jonas:这里的原因也是 command.com/cmd 没有真正的通用命令/参数解析器,因为它不是必需的。与 Unix 不同,Windows 上的进程只得到一串参数,而不是一个数组。因此,命令处理器不需要对进程名称进行任何解析(即直到第一个未加引号的空格)。内置命令(`cd` 等)甚至更旧,我什至不确定当时的解析器不是用汇编程序编写的 - 内置命令的整个解析不一致并且充满惊喜,主要是因为它是有机种植的而不是指定的。 (2认同)

Ove*_*ind 18

cd..命令是正确的,它的定义与command.com后来被命名为cmd.exe.

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

  • 我想主要问题是该命令不能“在语法上不正确”,因为语法_未在任何地方正式指定_,所以如果主要实现(cmd.exe 和/或 MS-DOS)接受它,那么它必须是正确的。 (8认同)
  • @JonasKöritz:因为语法从来都不是命令空间参数。 (6认同)
  • 另外,CD 不是程序,而是内部命令。类似于 Echo 也是一个内部命令,它不需要有空间来工作。`echo.` 也能正常工作,它会打印一个空行。 (3认同)
  • @Overmind echoe 也不起作用,所以它与 cd、echo、md 等相同。 (2认同)
  • @JonasKöritz ,`.` 没有删除,只是添加了一个空格。`md.test` 和 `md .test` 都创建了目录 `.test`。输入 `cd.test` 和 `cd .test` 将进入目录 `.test`。 (2认同)

Jul*_*les 11

这是一个向后兼容性黑客。

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

如今, '。' 可以出现在文件名中。这会导致如何解析命令的一些复杂性,但 shell仍将.不属于确切文件名的a 识别为参数的开头。这在很大程度上是必要的,因为数百万用户已经习惯于键入cd..或拥有包含该echo.命令或任何数量的其他类似命令的大量批处理文件。