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

Windows batch files: .bat vs .cmd?

据我所知,.bat是旧的16位命名约定,.cmd用于32位窗口,即从NT开始。但是我仍然可以在任何地方看到.bat文件,它们使用任何一个后缀的工作方式似乎都完全相同。假设我的代码永远不需要在NT之前的任何东西上运行,那么我命名批处理文件的方式是否真的很重要,或者是否有人用错误的后缀等待我?


从Mark Zbikowski自己发布的这个新闻组:

The differences between .CMD and .BAT as far as CMD.EXE is concerned
are: With extensions enabled, PATH/APPEND/PROMPT/SET/ASSOC in .CMD
files will set ERRORLEVEL regardless of error. .BAT sets ERRORLEVEL
only on errors.

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

  • 在.bat文件中保持其非0值
  • 在.cmd文件中重置为0。


以下是本主题中各种答案和引用的参考资料的核实信息汇编:

  • command.com是MS-DOS中引入的16位命令处理器,也用于Win9X系列操作系统。
  • cmd.exe是WindowsNT中的32位命令处理器(64位WindowsOSE也有64位版本)。cmd.exe从来不是Windows9x的一部分。它起源于OS/2版本1.0,而cmd的OS/2版本开始于16位(不过,它是一个完全成熟的保护模式程序,具有像start这样的命令)。WindowsNT从OS/2继承了cmd,但WindowsNT的win32版本是从32位开始的。虽然OS/2在1992年变成了32位,但它的cmd仍然是一个16位的OS/2 1.x程序。
  • ComSpecenv变量定义由.bat.cmd脚本启动的程序。(从winnt开始,默认为cmd.exe。)
  • cmd.execommand.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

    执行令:

    如果脚本的.bat和.cmd版本(test.bat,test.cmd)都在同一文件夹中,并且在不使用扩展名(test)的情况下运行脚本,则默认情况下,脚本的.bat版本将运行,即使在64位Windows 7上也是如此。执行顺序由pathext环境变量控制。有关详细信息,请参见命令提示执行文件的顺序。

    参考文献:

    • 命令提示符
    • 命令程序

    维基百科:命令shell的比较


    这些答案有点太长,主要集中在交互使用上。脚本编写的重要区别在于:

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

    默认情况下,在Windows 2000或更高版本下的.bat和.cmd文件中,命令扩展名都处于打开状态。

    2012年及以后,我建议只使用.cmd


    不-一点关系都没有。在NT上,.bat和.cmd扩展名都会使cmd.exe处理器以完全相同的方式处理文件。

    有关ms-technet中Winnt类系统上command.com与cmd.exe的其他有趣信息(http://technet.microsoft.com/en-us/library/cc723564.aspx):

    This behavior reveals a quite subtle
    feature of Windows NT that is very
    important. The 16-bit MS-DOS shell
    (COMMAND.COM) that ships with Windows
    NT is specially designed for Windows
    NT. When a command is entered for
    execution by this shell, it does not
    actually execute it. Instead, it
    packages the command text and sends it
    to a 32-bit CMD.EXE command shell for
    execution. Because all commands are
    actually executed by CMD.EXE (the
    Windows NT command shell), the 16-bit
    shell inherits all the features and
    facilities of the full Windows NT
    shell.


    回复:显然,当command.com被调用是一个复杂的谜;

    几个月前,在一个项目的过程中,我们必须弄清楚为什么我们想要在cmd.exe下运行的一些程序实际上是在command.com下运行的。所讨论的"程序"是一个非常旧的.bat文件,仍然每天运行。

    我们发现批处理文件在command.com下运行的原因是它是从一个.pif文件(也很古老)启动的。由于只有通过PIF才可用的特殊内存配置设置变得不相关,因此我们将其替换为传统的桌面快捷方式。

    从快捷方式启动的同一批文件在cmd.exe中运行。当你想到它时,这是有道理的。我们花了这么长时间才弄明白这一点的部分原因是,我们忘记了它在创业集团中的项目是一个PIF,因为它自1998年开始生产。


    由于最初的文章是关于使用.bat或.cmd后缀的结果,所以不一定是文件中的命令…

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

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

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


    不过,在Windows7上,BAT文件也有这样的区别:如果在同一目录中创建了test.bat和test.cmd文件,并且在该目录中运行了test,那么它将运行BAT文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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>


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


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


    稍微偏离主题,但您考虑过Windows脚本宿主吗?你可能会发现它更好。


    我相信如果您将comspec环境变量的值更改为%systemroot%system32cmd.exe,那么文件扩展名是.bat还是.cmd并不重要。我不确定,但这可能是WinXP及更高版本的默认设置。


    扩展没有区别。command.com处理文件与cmd.exe之间存在细微的差异


    我发现了一个区别:EnableDelayedExpansion.cmd文件中是必需的。如果与.bat文件一样,默认情况下是隐式的。(Windows 10)

    1
    2
    3
    4
    5
    dir *? | find /i"FOOBAR"
    if ERRORLEVEL 0             (
    set result="found"  ) else  (
    set result="not found"  )
    echo %result%

    这在.bat中有效,但在.cmd文件中始终是found。将line 2更改为以下内容使其按预期工作:

    1
    if %ERRORLEVEL% equ 0       (

    最后,对于.cmd文件,这是正确的:

    1
    2
    3
    4
    setLocal EnableDelayedExpansion
    ...
    if !ErrorLevel! equ 1       (
    ...


    差异:

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

    您可以在执行脚本文件时遇到这种情况,然后在执行完成之前对其进行编辑。BAT文件会被这个弄得一团糟,但是命令文件不会。