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

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

当键入时cd..,如果中间没有空格cd..Windows 命令提示符会切换到父文件夹。这种行为有什么解释吗?该命令不符合command<space>arguments

正在工作但不应该吗?

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

回声..

答案1

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

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

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

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

现在,这个问题还被问到回声命令:这是一个不寻常的例外,因为我认为echo.是 DOS 专家所熟知的。这可能已被记录下来。至少在 Win7 的命令,如果命令以“echo.",则第一个句点将被忽略。因此,"echo..hi“ 变成 ” 的输出.hi“。这样做的原因是”echo.“可用于打印空白行。相比之下,在 Unix 中,您只需运行“echo”命令本身。但是在 DOS 中,运行“echo“命令本身将输出当前”回声“设置。同样,DOS 处理“Echo *Off*“ 和 ”Echo *On*“作为改变当前回显设置的特殊值。如果你真的想打印单词“Off“, 然后 ”Echo.Off“ 可以解决问题(至少对于较新版本的 Microsoft命令命令行解释器。

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


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

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

下面是一个证明内部命令具有优先权的示例。(我还演示了鲜为人知的使用双冒号作为注释的功能,这在批处理文件中也很好用。从技术上讲,在批处理文件中,它被处理为 GOTO 无法到达的标签,最终比 REM 命令更快。)

C:\某物>MD 光盘
C:\某物>回声回显子目录>> cd\a.bat
C:\某物>MD \一个
C:\某物>.\cd\a.bat
子目录

C:\某物>:: 从子目录运行
C:\某物>光盘
目录:\a>:: 这改变了我当前的目录,所以光盘优先

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

这种对不太常见行为的探索(因为大多数目录中可能没有句号)促使我更新了我的发现。事实证明光盘命令实际上的行为更类似于复制命令比我最初想象的要好。

虽然我最初认为光盘复制命令的行为有所不同,我现在发现这是因为我提供的名称的模式。不过,我回顾了我之前的结果,并确定我之前记录的测试确实有助于显示名称包含句点和扩展名时与不包含句点和扩展名时发生的一些差异。所以,我仍然在下面包含我以前的发现(大部分没有改变,但有一些非常小的更新,所以我说的是正确的)。

下面是一个示例复制具有完整路径,不使用与以下相同的优先级(有利于内部命令)光盘当不使用扩展时:

C:\某物>echo echo 根>> \try.bat
C:\某物>md 复制
C:\某物>echo echo 子目录>>copy\try.bat
C:\某物>.\copy\try.bat 从子目录运行
子目錄

C:\某物>复制\try.bat
子目錄

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

C:\某物>:: 好的,太棒了。但是这样就不会检查子目录了:
C:\某物>复制..\try.bat
        已复制 1 个文件。

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

我的早期研究结果表明这些结果表明命令行 shell 优先:

  • 到文件系统(而不是内部复制命令)在内部命令名称后指定反斜杠时
  • 到内部光盘命令(而不是文件系统)在内部命令名称后指定反斜杠时。
  • 到内部复制在内部命令名称后立即指定句点时,命令(而不是文件系统)。

这清楚地表明,复制命令(带有完整文件名,包括扩展名)和光盘命令(不包含目录名的扩展名)。使用反斜杠时,复制命令(带有完整的文件扩展名)将首先检查文件系统,但光盘命令不会执行(如果目录不包含扩展名)。

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

实际上,即使我似乎只是证明了我刚才所说的每一件事,这些要点也并不完全准确。问题是,这些要点列表不够精确,不足以完全准确。(我没有精确列出要点,以便可以相对容易地比较和检查这些要点。)

然而,更准确地说,第一点应该指出命令行 shell 优先:

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

下面可以解释我为什么做出这样的区分:

C:\其他地方>回声此线路需要 UAC 提升>> \需要
C:\其他地方>回声此线路需要 UAC 提升>> \需要文本文件
C:\其他地方>md.\复制
C:\其他地方>回声@Echo 子目录>> 复制\needex.bat
C:\其他地方>.\复制\needext
子目录

C:\其他地方>复制\needex.bat
子目录

C:\其他地方>复制\needex
        已复制 1 个文件。

C:\其他地方>:: 下几行也需要 UAC
C:\其他地方>删除 \needext
C:\其他地方>删除\needext.bat

(请注意最后复制命令查找名为\needext,因为内部复制命令被使用。文件\需要文本文件只是为了帮助轻松表明它从未被包含单词的命令行使用过复制

在这一点上,我发现了一些不一致之处(与复制命令)时,使用反斜杠……

接下来,我将证明这些命令之间存在一定的一致性。(所以,有时是一致的……嗯……。我们可能只有不一致的一致性。)接下来我要展示的是光盘命令的行为确实类似于复制命令。复制命令使用内部命令,光盘命令。

C:\某物>md.\t更多

C:\某物>cd.\yetmore

C:\something\yetmore>MD。\MD
C:\something\yetmore>回声回显子目录>> md\测试.bat
C:\something\yetmore>.\md.\测试
子目录

C:\something\yetmore>md.\测试

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

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

C:\something\yetmore>.\cd.\测试
子目录

C:\something\yetmore>cd.\测试
C:\something\yetmore\test>::内部命令与一个句点一起使用
C:\something\yetmore\test>光盘..
C:\something\yetmore>.\cd..\测试
子目录

C:\something\yetmore>cd..\测试
C:\某物\测试>:: 使用两个句点时,内部命令也优先

因此,在最初的测试中,主要关注的是光盘复制命令(还有一些额外的用法MD还有一点德尔),我们真正让文件系统优先的唯一一次是复制命令,然后文件系统仅在使用完整路径时才优先。

经过后续审查,我发现光盘命令在使用扩展时也赋予了文件系统优先级。至少这意味着内部命令的处理方式更加一致。但是,这也意味着我们会根据文件系统对象(文件或目录)的名称获得不同的行为。这似乎表明该行为使用了一些非常非常模糊的内部逻辑。因此,我可能会考虑将这种行为用于不同的操作系统不安全去做。

答案2

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

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

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

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

echo...
..

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

echo .

或者,延伸一下,这是:

echo.

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

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

答案3

该命令是正确的,并且它在后来被命名的cd..原始命令解释器中是这样定义的。command.comcmd.exe

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

答案4

现代 Powershell 定义的语法更清晰,但cd..仍然有效。

但是我注意到这只是一个脚本:

> get-command "cd.." | select *

ScriptBlock         : Set-Location ..
CommandType         : Function
. . .

cd本身是 的别名Set-Location)。

同时cd.(等等)失败。

相关内容