ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

J
Jean-François Corbett

来自 Mark Zbikowski 本人的 this news group posting

就 CMD.EXE 而言,.CMD 和 .BAT 之间的区别在于: 启用扩展后,.CMD 文件中的 PATH/APPEND/PROMPT/SET/ASSOC 将设置 ERRORLEVEL 而不管错误。 .BAT 仅在错误时设置 ERRORLEVEL。

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

在 .bat 文件中保持其非 0 值

在 .cmd 文件中重置为 0。


这是否意味着使用 .bat 脚本不会在成功时返回 ERRORLEVEL 0 值?如果这是真的,我从来没有注意到它。
我认为这意味着如果 ERRORLEVEL 设置为非 0,那么您运行其中一个命令,它将在 .bat 文件中单独保留(非 0),但在 .cmd 文件中重置为 0。但是,Windows 就是这样,它很可能实际上会导致一个无实体的声音告诉你,在 Pig Latin 中,“如果你这么在乎,你自己重置 ERRORLEVEL!”。
我认为这是说只有那些特定的命令会执行不同的设置/未设置操作。其他人会正常工作
注 - APPEND 命令已替换为未记录的 DPATH 命令,尽管 DPATH /? 仍将该命令列为 APPEND。此外,该 Wiki 文章此后大部分已得到更正,但未列出 DPATH。
FTYPE 命令也仅在由 .cmd 脚本执行时将 ERRORLEVEL 清除为 0。
1
19 revs, 10 users 79%

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

command.com 是 MS-DOS 中引入的 16 位命令处理器,也用于 Win9x 系列操作系统。 cmd.exe 是 Windows NT 中的 32 位命令处理器(64 位 Windows 操作系统也有 64 位版本)。 cmd.exe 从来都不是 Windows 9x 的一部分。它起源于 OS/2 版本 1.0,而 OS/2 版本的 cmd 开始于 16 位(但它仍然是一个完全成熟的保护模式程序,带有诸如 start 之类的命令)。 Windows NT 从 OS/2 继承了 cmd,但 Windows NT 的 Win32 版本从 32 位开始。虽然 OS/2 在 1992 年变成了 32 位,但它的 cmd 仍然是一个 16 位的 OS/2 1.x 程序。 ComSpec env 变量定义了由 .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(以前存在,已增强)

功能:调用:标签

执行顺序:

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

参考:

命令文件

命令网

维基百科: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。
克里斯:请参阅当前版本的 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 文件之间的区别,所有其他条件都相同。
G
Gringo Suave

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

.cmd 可防止在非 NT 系统上意外执行。

.cmd 启用内置命令以在成功时将 Errorlevel 更改为 0。

不是那么令人兴奋,是吗?

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

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


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

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

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

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


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

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

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

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

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


这是什么操作系统? XP之前的东西?
t
tvCa

尽管如此,在 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 执行贪婪完成。
@大卫:不正确。发生这种情况是因为在 PATHEXT 变量中 .BAT 扩展名放在 .CMD 之前(如本答案所示)。如果您在 PATHEXT 中修改此顺序,将改为执行 test.cmd。
嗯,我希望它们是另一个顺序;我猜 MS 一定已经发现(或假设)某些现有软件附带了具有相同基本名称的 .CMD 文件和 .BAT 文件,其中 .CMD 文件当然不打算作为(尚未发布的)cmd 的输入。 exe,但也可以是其他任何东西:例如,其他 shell 的命令、应用程序读取的配置脚本或某种应用程序二进制文件。 (至少,这是我对 MS 以看似次优的行为结束的通常方式的理解。)
还值得注意的是,无论扩展名如何,当前目录都位于 PATH 环境变量中的其他目录之前。
R
Rob at TVSeries.com

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

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

在命令行输入 filename 或 filename.bat 将运行 .bat 文件

要运行 .cmd 文件,您必须输入 filename.cmd


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

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


应该不会影响速度。 .bat 在 NT 的 DOS 下不运行。 VDM 仅在程序需要时才启动,并且在 64 位 Windows 中甚至不支持,尽管我相信 .bat 是。
M
Mofi

.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 变量仍然会改变状态。
P
Patrick Cuff

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


W
Waldo

扩展没有区别。

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


g
grey

区别:

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

您可以在执行脚本文件时遇到此问题,然后在执行完成之前对其进行编辑。 bat 文件会因此而混乱,但 cmd 文件不会。


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