Windows 批处理文件:.bat 与 .cmd?

Posted

技术标签:

【中文标题】Windows 批处理文件:.bat 与 .cmd?【英文标题】:Windows batch files: .bat vs .cmd? 【发布时间】:2010-09-14 00:29:05 【问题描述】:

据我了解,.bat 是旧的 16 位命名约定,.cmd 用于 32 位 Windows,即以 NT 开头。但是我继续在各处看到 .bat 文件,并且使用任何一个后缀它们的工作方式似乎完全相同。假设我的代码永远不需要在 NT 之前的任何东西上运行,那么我以哪种方式命名批处理文件真的很重要,还是有一些 gotcha 使用错误的后缀在等待我?

【问题讨论】:

只是为了增加混乱,我们现在也有 .ps1 文件。 如果我没记错的话 .ps1 文件应该是 Windows Power Shell 文件。不过我可能是错的。 .ps1 是一个 Windows PowerShell 文件,它是与 .bat/.cmd 批处理文件完全不同的语言。 【参考方案1】:

来自this news group postingMark Zbikowski本人:

.CMD 和 .BAT 就 CMD.EXE 而言的区别 是:启用扩展后,.CMD 中的 PATH/APPEND/PROMPT/SET/ASSOC 无论错误如何,文件都会设置 ERRORLEVEL。 .BAT 设置 ERRORLEVEL 仅针对错误。

换句话说,如果 ERRORLEVEL 设置为非 0,然后您运行其中一个命令,则生成的 ERRORLEVEL 将是:

在 .bat 文件中单独保留其非 0 值 在 .cmd 文件中重置为 0。

【讨论】:

这是否意味着使用 .bat 脚本不会在成功时返回 ERRORLEVEL 0 值?如果这是真的,我从来没有注意到。 我认为这意味着如果 ERRORLEVEL 设置为非 0,那么您运行其中一个命令,它将在 .bat 文件中单独存在(非 0)但在 .bat 文件中重置为 0 .cmd 文件。但是,Windows 就是这样,它很可能实际上会导致一个无实体的声音告诉你,用 Pig Latin 来告诉你,“如果你这么在乎,你自己重置 ERRORLEVEL!”。 我认为只有那些特定的命令会执行不同的设置/未设置操作。其他人会正常工作 我现在明白了。我更新了我的要点。显然,在调用set var=.. 语句时,它不会(重新)设置错误级别。这很奇怪,因为我认为这是预期的行为。可以为两者提出论据。我会坚持使用 .bat 文件。 :-) 注意 - APPEND 命令已替换为未记录的 DPATH 命令,尽管DPATH /? 仍将该命令列为 APPEND。此外,该 Wiki 文章此后大部分已得到更正,但未列出 DPATH。【参考方案2】:

以下是来自该线程中各种答案和引用参考文献的已验证信息的汇编:

    command.com是MS-DOS引入的16位命令处理器,也用于Win9x系列操作系统。 cmd.exe 是 Windows NT 中的 32 位命令处理器(64 位 Windows 操作系统也有 64 位版本)。 cmd.exe 从来都不是 Windows 9x 的一部分。它起源于 OS/2 版本 1.0,而cmd 的 OS/2 版本开始是 16 位的(但它仍然是一个完全成熟的保护模式程序,带有像 start 这样的命令)。 Windows NT 从 OS/2 继承了cmd,但 Windows NT 的 Win32 版本从 32 位开始。尽管 OS/2 在 1992 年推出了 32 位,但其 cmd 仍然是 16 位 OS/2 1.x 程序。 ComSpec 环境变量定义了由.bat.cmd 脚本启动的程序。 (从 WinNT 开始,默认为 cmd.exe。) cmd.exe 向后兼容 command.com。 为cmd.exe 设计的脚本可以命名为.cmd,以防止在Windows 9x 上意外执行。此文件扩展名也可以追溯到 OS/2 版本 1.0 和 1987。

以下是command.com 不支持的cmd.exe 功能列表:

长文件名(超过 8.3 格式) 命令历史记录 制表符补全 转义字符:^(用于:\ & | > < ^) 目录栈:PUSHD/POPD 整数运算:SET /A i+=1 搜索/替换/子字符串:SET %varname:expression% 命令替换:FOR /F(以前存在,已增强) 功能:CALL :label

执行顺序:

如果脚本(test.bat、test.cmd)的 .bat 和 .cmd 版本都在同一个文件夹中,并且您在没有扩展名(test)的情况下运行脚本,默认情况下,脚本的 .bat 版本将即使在 64 位 Windows 7 上也可以运行。执行顺序由 PATHEXT 环境变量控制。详情请见Order in which Command Prompt executes files。

参考资料:

cmd.exe command.com

***:Comparison of command shells

【讨论】:

几个小问题: 1) .bat 不一定会调用 command.com - 显然,何时调用 command.com 有点复杂; 2) command.com 是在 MS-DOS 中引入的; 3) cmd.exe 可以运行大多数command.com 脚本,但是command.com 的一些小东西在cmd 中不起作用。 cmd.exe 我相信是在 NT 4.0 中引入的,而不是 Windows 95。 Chris:查看当前版本的 Wikipedia 文章,尤其是。 Mark Zbikowski 在groups.google.com/group/… 的评论 只是添加一些关于此事的信息:dir filename 与 command.com 中的dir filename.* 相同; cmd.exe 中需要通配符。在 command.com rem Create an empty file > empty.txt 工作;不在 cmd.exe 中。 这似乎与OP的问题有关,即.bat和.cmd之间的区别,而不是command.com和cmd.exe之间的区别。当我读到它时,问题是关于 .bat 文件和 .cmd 文件之间的区别,所有其他条件都相同。【参考方案3】:

这些答案有点太长了,而且侧重于交互式使用。脚本的重要区别是:

.cmd 防止在非 NT 系统上无意执行。 .cmd 启用内置命令以在成功时将 Errorlevel 更改为 0。

没那么令人兴奋,是吗?

过去,.cmd 文件中启用了许多附加功能,称为命令扩展。但是,在 Windows 2000 及更高版本下,它们现在默认为 .bat.cmd 文件启用。

底线: 在 2012 年及以后,我建议只使用.cmd

【讨论】:

IMO,这是重点。当您想确保它们不在较旧的 16 位操作系统上执行时,或者如果您不确定它们是否能正常工作,您可以使用 .cmd 作为新脚本的扩展名。 我非常感谢在大量无用的大学课堂式答案中提供简洁、务实和清晰的答案。 我是大学教授,我同意@Liquid Core!简洁、务实、清晰的答案是我们学习的方式(当我们还不知道某事时)。然后,不知何故,一旦我们理解了它,我们就会有一种用抽象和难以理解的方式来解释它的冲动。诡异的。很好的观察!【参考方案4】:

不 - 这一点都不重要。在 NT 上,.bat 和 .cmd 扩展名都导致 cmd.exe 处理器以完全相同的方式处理文件。

来自 MS TechNet (http://technet.microsoft.com/en-us/library/cc723564.aspx) 的有关 WinNT 类系统上 command.com 与 cmd.exe 的其他有趣信息:

这种行为揭示了一个相当微妙的 Windows NT 的一个非常重要的功能 重要的。 16 位 MS-DOS 外壳 (COMMAND.COM) 随 Windows NT 是专门为 Windows 设计的 新台币。输入命令时 由这个 shell 执行,它不会 实际执行它。相反,它 打包命令文本并发送 到 32 位 CMD.EXE 命令外壳 执行。因为所有命令都是 实际由 CMD.EXE 执行( Windows NT 命令外壳),16 位 shell 继承了所有的特性和 完整的 Windows NT 设施 外壳。

【讨论】:

这可能很重要;正如您的链接文字所提到的,差异是微妙的。 您可以通过在命令行中指定来强制 command.com 执行 dos 命令。请参阅 command /c ver 与启动 command.com 并输入 ver. 名字很重要 :D 看到很多 .bat 来自过去!使用 .cmd!也不敢相信NT今天还在用…… @hfrmobile:当我提到“NT”时,基本上是指我们基于 NT(而不是 9x)的所有 Windows 版本。所以本质上是 NT、Win2k 以及自 XP 以来用于桌面或服务器的所有 Windows 版本。并且文件的名称可以洞察编写文件的人的思维方式和编码风格,但就解释器而言,没有区别。【参考方案5】:

RE:显然,何时调用 command.com 有点复杂;

几个月前,在一个项目的过程中,我们不得不弄清楚为什么我们想在 CMD.EXE 下运行的一些程序实际上是在 COMMAND.COM 下运行的。有问题的“程序”是一个非常古老的 .BAT 文件,仍然每天运行。

我们发现批处理文件在 COMMAND.COM 下运行的原因是它是从 .PIF 文件(也很古老)启动的。由于只能通过 PIF 获得的特殊内存配置设置已变得无关紧要,因此我们将其替换为传统的桌面快捷方式。

从快捷方式启动的同一个批处理文件在 CMD.EXE 中运行。当您考虑它时,这是有道理的。我们花了这么长时间才弄明白的部分原因是我们忘记了它在启动组中的项目是 PIF,因为它从 1998 年就开始生产了。

【讨论】:

这是什么操作系统? XP 之前的东西?【参考方案6】:

不过,在 Windows 7 上,BAT 文件也有这样的区别:如果您曾在同一目录中创建文件 TEST.BAT 和 TEST.CMD,并在该目录中运行 TEST,它将运行 BAT 文件。

C:\>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

C:\Temp>echo echo bat > test.bat

C:\Temp>echo echo cmd > test.cmd

C:\Temp>test

C:\Temp>echo bat
bat

C:\Temp>

【讨论】:

之所以这样做是因为 test.bat 按字母顺序排列在 test.cmd 之前。 Windows 贪婪完成。 @David:不正确。发生这种情况是因为在 PATHEXT 变量中 .BAT 扩展名放在 .CMD 之前(如本答案所示)。如果您在 PATHEXT 中修改此顺序,则会改为执行 test.cmd。 嗯,我希望它们是另一个顺序;我猜 MS 一定已经发现(或假设)某些现有软件提供了具有相同基本名称的 .CMD 文件和 .BAT 文件,其中 .CMD 文件当然不打算作为(尚未发货的)cmd 的输入。 exe,但可能是任何数量的其他东西:例如,某些 other shell 的命令、应用程序读取的配置脚本或某种应用程序二进制文件。 (至少,这是我对 MS 以看似次优的行为结束的通常方式的理解。) 另外值得注意的是,在PATH 环境变量中,当前目录位于其他目录之前,无论扩展名如何。【参考方案7】:

由于原始帖子是关于使用 .bat 或 .cmd 后缀的后果,因此不一定是文件内部的命令...

.bat 和 .cmd 之间的另一个区别是,如果存在具有相同文件名和扩展名的两个文件,则:

在命令行输入文件名文件名.bat会运行.bat文件

要运行.cmd文件,你必须输入文件名.cmd

【讨论】:

嗯?如果我将 cmd 文件放在我的目录中,我不必指定文件扩展名来调用它。示例: echo notepad.exe %* > np.cmd 然后,如果我只输入“np mytextfilename.txt”,它将调出记事本。我不必输入“np.cmd”来调用它。 @stimpy77:如果 np.cmd 是唯一具有该名称的文件,则为 true,但 “如果存在具有相同文件名和扩展名的两个文件”,那么执行 .cmd 的唯一方法是包含其扩展名... 这是解决任何 shell 歧义的必要条件,与 .cmd 与 .bat 之间的技术差异无关。这可能是因为 filename.bat 按字母顺序在 filename.cmd 之前。 它实际上取决于PATHEXT 环境变量。如果未指定扩展名,则扩展名出现的顺序是优先顺序。还值得一提的是,没有必要为文件指定扩展名,其扩展名出现在 env 变量中。 我注意到这个答案是从 2014 年开始的 - 它仍然正确吗?...(我从来不需要专门添加 .cmd 来运行 MyScript.cmd - AFAIK C:\> MyScript 工作正常(对于.cmd.bat 文件)。【参考方案8】:

批处理中的所有工作都应该在 cmd 中工作; cmd 提供了一些用于控制环境的扩展。 此外,cmd 由新的 cmd 解释器执行,因此在 NTVDM 模拟 16 位环境下运行 bat 时应该更快(在短文件上不明显)和更稳定

【讨论】:

不应该对速度产生任何影响。 .bat 不能在 NT 的 DOS 下运行。 VDM 仅在程序需要时才启动,并且在 64 位 Windows 中甚至不支持,尽管我相信 .bat 是。【参考方案9】:

.cmd 和 .bat 文件的执行是不同的,因为在 .cmd 错误级别变量中,它可以在受命令扩展影响的命令上更改。真的是这样。

【讨论】:

粗略的^.^ 每种使用的命令语言存在差异(.bat 文件获得兼容版本)。其中一些可以通过这里的脚本来说明:@echo off&setlocal ENABLEEXTENSIONS call :func&&echo/I'm a cmd||echo/I'm a bat goto :EOF :func md;2>nul set var=1 在 .cmd 文件中,每个命令都会设置错误级别,在 .bat 文件中,某些命令会保持错误级别不变,如接受的答案中所述 BAT 的创建是为了与 DOS 的命令解释器 COMMAND.COM 交互。微软在他们的新解释器 CMD 中采用了大部分 DOS 命令。 EXE文件。创建 CMD 是为了与 CMD.EXE 交互,它破坏了与 COMMAND.COM 的兼容性。主要以他们如何处理错误级别变量而闻名。使用 BAT 时,只有在发生实际错误时才会更改此变量,并且在每个命令执行成功时不会发生状态更改。这对于 CMD 来说是不正确的,因为即使没有发生错误,errorlevel 变量仍然会改变状态。【参考方案10】:

我相信,如果您将 ComSpec 环境变量的值更改为 %SystemRoot%system32\cmd.exe(CMD),那么文件扩展名是 .BAT 还是 .CMD 都没有关系。我不确定,但这甚至可能是 WinXP 及更高版本的默认设置。

【讨论】:

【参考方案11】:

扩展没有区别。

处理文件的COMMAND.COM 与处理文件的CMD.EXE 之间存在细微差别。

【讨论】:

【参考方案12】:

区别:

.cmd 文件在执行之前被加载到内存中。 .bat 文件执行一行,读取下一行,执行该行...

当您执行一个脚本文件然后在它完成执行之前对其进行编辑时,您可能会遇到这种情况。 bat 文件会因此而混乱,但 cmd 文件不会。

【讨论】:

正如已经建立的那样,ComSpec env 变量定义了启动哪个程序,你本质上是说 command.com 一次读取一行文件,而 cmd.exe 将文件预加载到记忆?你能引用这方面的参考吗? Vista 和 XP 是错误的,两种文件类型都是逐行读取的。如果您暂停 .cmd 或 .bat 文件并对其进行编辑,则会执行新代码 你可能在想.btm ("batch to memory") files as employed with JP Software's replacement command interpreters。 人们可能会争论它是否是逐行的,因为如果您在命令文件的中间暂停执行并在开头添加一个字符,则在恢复时解析器将关闭一个字符,可能会抛出关闭脚本的其余部分。 你不应该争论 .bat 和 .cmd 在这种方式上没有区别。两者总是逐行读取。不信可以试一试。制作一个包含echo 1&pause 的批处理文件,然后执行它。您将看到1Press any key to continue...。暂停时使用外部编辑器添加新行 echo 2&pause。按一个键。您将看到2Press any key to continue...。您甚至可以尝试在开头添加echo 3&pause。当您再次按下某个键时,您将看到2

以上是关于Windows 批处理文件:.bat 与 .cmd?的主要内容,如果未能解决你的问题,请参考以下文章

Perl-4 Windows批处理(cmd/bat)常用命令大全 2020-12-20

windows cmd bat处理文件

Windows批处理(cmd/bat)常用命令小结

Windows 批处理(cmd/bat)常用命令教程

开发环境Java 文件生成 Windows 系统 .bat 批处理文件并自动执行 ( 输出 GB2312 格式处理中文乱码 | 换行 | Runtime 执行 Cmd 命令 )

Windows批处理(cmd/bat)常用命令小结