Windows批处理文件:.bat和.cmd有什么区别?

888
据我所了解,.bat 是旧的16位命名约定,而.cmd是用于32位Windows,例如从NT开始。但我仍然到处看到.bat文件,并且无论使用哪个后缀,它们似乎都能正常工作。假设我的代码永远不需要在NT之前的任何操作系统上运行,那么我将批处理文件命名为哪种方式真的很重要吗?或者说如果我使用错误的后缀会有一些问题等待着我吗?

64
如果我没记错的话,.ps1文件应该是Windows PowerShell文件,但我可能错了。 - CMS_95
10
.ps1是Windows PowerShell文件,它与.bat/.cmd批处理文件完全不同。 - xjcl
12个回答

541

根据这篇新闻组帖子,由Mark Zbikowski本人撰写:

CMD.EXE在处理.CMD和.BAT文件时的区别在于:启用扩展名后,.CMD文件中的PATH/APPEND/PROMPT/SET/ASSOC命令会在出现错误时设置ERRORLEVEL。而.BAT文件只有在出现错误时才会设置ERRORLEVEL。

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

  • 在.bat文件中,ERRORLEVEL保持不变,仍为非0值
  • 在.cmd文件中,ERRORLEVEL将被重置为0。

6
这是否意味着使用 .bat 脚本在成功时不会返回 ERRORLEVEL 0 值?如果是这样,我从未注意到过。 - djangofan
44
我认为这意味着,如果ERRORLEVEL被设置为非0,在.bat文件中运行这些命令时,它将保持原样(非0),但在.cmd文件中将被重置为0。但是,由于Windows的特殊性,很可能会出现一个无头声音用Pig Latin告诉你,“如果你很在意,请自行重置ERRORLEVEL!” - MadScientist
8
我认为它的意思是只有特定的命令才会执行不同的设置/未设置操作,其他命令将像正常情况下一样工作。 - PsychoData
3
注意 - APPEND 命令已被未记录的 DPATH 命令所取代,尽管 DPATH /? 仍将该命令列为 APPEND。此外,维基文章已经进行了大部分修正,但未列出 DPATH 命令。 - dbenham
3
仅当由.cmd脚本执行时,FTYPE命令才会将ERRORLEVEL清除为0。 - dbenham
显示剩余5条评论

480
以下是本主题串中各个回答和引用参考资料的验证信息汇编:
0. `command.com` 是引入MS-DOS中的16位命令处理器,也被Win9x系列操作系统使用。 1. `cmd.exe` 是Windows NT中的32位命令处理器(64位Windows OSes也有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程序。 2. `ComSpec` 环境变量定义了由 `.bat` 和 `.cmd` 脚本启动的程序是哪个。(从WinNT开始,默认为 `cmd.exe`。) 3. `cmd.exe` 向后兼容 `command.com`。 4. 专门针对 `cmd.exe` 设计的脚本可以命名为 `.cmd`,以防止在Windows 9x上意外执行。该文件名扩展名也可以追溯到OS/2版本1.0和1987年。
以下是 `cmd.exe` 支持但 `command.com` 不支持的功能列表:
- 长文件名(超过8.3格式) - 命令历史记录 - Tab键补全 - 转义字符:`^` (用于:`\ & | > < ^`) - 目录堆栈:`PUSHD`/`POPD`
  • 整数算术: SET /A i+=1
  • 搜索/替换/子字符串: SET %varname:expression%
  • 命令替换: FOR /F(之前已存在,现在已得到增强)
  • 函数: CALL :label
  • 执行顺序:

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

    参考资料:

    wikipedia:Comparison of command shells


    10
    几个小细节:1).bat 不一定会调用 command.com - 显然当 command.com 被调用时是一个比较复杂的谜团;2)command.com 是在 MS-DOS 中引入的;3)cmd.exe 可以运行大多数 command.com 脚本,但有一些不重要的 command.com 功能在 cmd 中不起作用。 - Michael Burr
    8
    我认为,cmd.exe是在NT 4.0中引入的,而不是Windows 95。 - FlySwat
    3
    别名和历史记录是控制台窗口(conhost.exe或csrss.exe)的功能,而不是cmd.exe。历史记录与F7弹出框集成。每个附加的程序都有自己的历史记录和别名,由console API管理,或通过doskey从命令行管理。 - Eryk Sun
    4
    关于这个问题,我想补充一些信息:在command.com中,dir filename相当于dir filename.*;在cmd.exe中需要使用通配符。在command.com中,执行rem Create an empty file > empty.txt可以创建一个空文件,但在cmd.exe中不行。 - Aacini
    12
    这段话的意思是:只有一点点内容与提问者的问题相关,那就是.bat和.cmd的区别,而不是command.com和cmd.exe的区别。从我的阅读中,这个问题是关于在其他条件相同的情况下,.bat文件和.cmd文件之间的区别。 - Stewart
    显示剩余10条评论

    176

    这些答案过于冗长,关注的是交互使用。脚本编程时的重要区别在于:

    • .cmd 防止在非NT系统上意外执行。
    • .cmd 使内置命令能够在成功时将错误级别更改为0。

    没什么激动人心的,对吧?

    以前有许多其他功能可以在 .cmd 文件中启用,称为命令扩展。然而,它们现在已默认在Windows 2000及以后的版本中启用了 .bat.cmd 文件。

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


    11
    我认为那是重点。当您想确保脚本不在旧的16位操作系统上运行,或者不确定是否能正常工作时,您可以使用.cmd作为较新脚本的扩展名。 - Oliver
    41
    我非常赞赏简明、实用和清晰的回答,而不是一大堆毫无用处、像上大学课一样的回答。 - Liquid Core
    17
    我是一名大学教授,我同意@Liquid Core的观点!简洁、实用、清晰的回答是我们学习的方式(当我们还不知道某些事情时)。然后,不知何故,一旦我们理解了它,就会感到有必要用抽象和难以理解的方式来解释它。奇怪。好的观察! - ProfDFrancis

    26

    不会,.bat和.cmd扩展名在NT上都会让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 shell(COMMAND.COM)是专门为Windows NT设计的。当该shell输入命令以便执行时,它实际上并不执行该命令。相反,它打包命令文本并将其发送到32位CMD.EXE命令shell以便执行。因为所有命令实际上都由CMD.EXE(Windows NT命令shell)执行,所以16位shell继承了完整的Windows NT shell的所有功能和设施。


    5
    可能会有影响,就像你的链接文字所提到的那样,差异是微妙的。 - Gringo Suave
    1
    你可以强制让 command.com 在命令行上执行一个 DOS 命令。查看 command /c ver 与启动 command.com 并键入 ver 的区别。 - phd443322
    名称很重要:D 从过去的人们看到了很多.bat!使用.cmd!而且无法相信NT今天仍在使用... - hfrmobile
    @hfrmobile:当我提到“NT”时,我基本上是指所有基于NT(而不是9x)的Windows版本。因此,基本上包括NT、Win2k以及自XP以来的所有桌面或服务器Windows版本。文件的名称可能会揭示编写该文件的人的思维方式和编码风格,但就解释器而言,并没有什么区别。 - Michael Burr

    21

    RE: 明显地,当调用command.com时有点复杂的奥秘;

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

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

    从快捷方式启动的相同批处理文件在CMD.EXE下运行。如果你好好想想,这是有道理的。我们花了很长时间才弄清楚其中的原因,部分原因是因为我们忘记了它在启动组中的项是一个PIF,因为它自1998年以来就一直在生产中使用。


    2
    这是什么操作系统?XP之前的版本? - phk

    20

    然而,在Windows 7上,批处理文件也有这样的区别:如果您在同一个目录下创建了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
    39
    @David:不是这样的。这是因为在“PATHEXT”变量中,.BAT扩展名排在.CMD之前(如此答案所示)。如果您修改PATHEXT中的顺序,test.cmd将被执行。 - Aacini
    嗯,我本来希望它们的顺序是相反的;我猜微软可能已经发现(或者假设)一些现有的软件使用相同的基本名称来发布.CMD文件和.BAT文件,其中.CMD文件当然不是作为(尚未发布的)cmd.exe的输入而设计的,但可以是许多其他东西:某些其他 shell的命令,应用程序读取的配置脚本或某种应用程序二进制文件,例如。(至少,这是我对微软通常出现看似次优行为的理解。) - SamB
    4
    值得注意的是,无论扩展名如何,当前目录在PATH环境变量中始终优先于其他目录。 - Turkeyphant

    13

    由于原始帖子涉及使用 .bat 或 .cmd 后缀名 的后果,而不一定是文件内部的命令...

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

    • 在命令行中输入 文件名文件名.bat 将运行 .bat 文件

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


    2
    嗯?如果我把一个cmd文件放在我的目录中,我不必指定文件扩展名来调用它。例如:echo notepad.exe %* > np.cmd然后,如果我只是输入“np mytextfilename.txt”,它会打开记事本。我不必输入“np.cmd”来调用它。 - Jon Davis
    3
    如果np.cmd是唯一具有该名称的文件,则此说法正确,但是,如果“存在两个具有相同文件名和这两个扩展名”的文件,则执行.cmd文件的唯一方法是包括其扩展名... - Aacini
    2
    这是解决任何 shell 歧义的必要条件,与 .cmd 与 .bat 之间的技术差异无关。这可能是因为按字母顺序排列,filename.bat 在 filename.cmd 之前。 - Jon Davis
    6
    实际上取决于 PATHEXT 环境变量。扩展名出现的顺序决定了没有指定扩展名时的优先顺序。值得一提的是,对于扩展名出现在环境变量中的文件,不必指定其扩展名。 - Ricardo Zorio
    我注意到这个答案来自2014年 - 它仍然正确吗?(我从未必须特别添加“.cmd”才能运行“MyScript.cmd” - 据我所知,“C:> MyScript”对于“.cmd”或“.bat”文件也可以正常工作。 - Martin

    9

    所有在批处理中工作的内容都应该可以在命令提示符(cmd)下工作;cmd提供了一些控制环境的扩展。此外,cmd是由新的cmd解释器执行的,因此应该更快(对于短文件不明显),并且更稳定,因为bat运行在NTVDM模拟的16位环境下。


    速度上不应该有任何区别。.bat在NT下不运行DOS。只有当程序需要时才会启动VDM,而且在64位Windows中甚至不支持它,尽管我相信.bat是支持的。 - Gringo Suave

    3

    .cmd和.bat文件执行不同,因为在.cmd中,errorlevel变量可以在受命令扩展影响的命令上发生改变。就是这样。


    当然,每个命令语言使用的命令都有所不同(.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` - zask
    6
    在 .cmd 文件中,每个命令都会设置 errorlevel 值;而在 .bat 文件中,一些命令会保持 errorlevel 的不变。这些情况已经在被接受的回答中做了描述。 - jeb
    2
    BAT是为了与DOS的命令解释器COMMAND.COM交互而创建的。微软采用了大部分DOS命令,将它们纳入了他们命名为CMD.EXE的新解释器中。CMD被创建用于与CMD.EXE进行接口,并且它与COMMAND.COM不兼容,主要以其处理errorlevel变量而闻名。在使用BAT时,只有在实际错误发生时才会更改此变量,并且每个命令成功执行时状态没有改变。但是CMD不同,即使没有错误发生,errorlevel变量也会发生变化。 - zask

    3

    我认为,如果您将ComSpec环境变量的值更改为%SystemRoot%system32\cmd.exe(CMD),那么文件扩展名是.BAT还是.CMD都无所谓。我不确定,但这可能是WinXP及以上版本的默认设置。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接