batch-file bat变量 - Windows批处理文件:.bat vs.cmd?




bat参数 bat命令 (13)

扩展没有区别。 处理文件与CMD.EXE的COMMAND.COM之间略有不同

据我了解, .bat是旧的16位命名约定, .cmd是32位Windows,即从NT开始。 但我继续在任何地方都看到.bat文件,而且它们似乎使用任一后缀完全相同。 假设我的代码永远不需要运行在比NT更早的任何东西上,那么我命名我的批处理文件的方式真的很重要,还是有一些通过使用错误的后缀等待我的问题?


作为一名Cmd程序员,并且遍布整个网络,你使用哪一个真正无关紧要,你可以在Windows 7上有一个.bat程序,并在Windows 10上运行它。但是如果你要它在Windows 10上,您可能无法在Windows 7上运行所有命令.cmd完全相同,并运行完全相同的程序和代码。

所有不同之处在于,它是同一个程序的不同名称,只要它连接到CMD.EXE ,它就会运行相同的命令。


尽管如此,在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>

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


区别:

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

你可以在执行脚本文件时遇到这种情况,然后在完成执行之前对其进行编辑。 蝙蝠文件将由此弄乱,但cmd文件不会。


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


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


以下是本主题中各种答案和引用参考文献的验证信息汇编:

  1. command.com是在MS-DOS中引入的16位命令处理器,也用于Win9x系列操作系统。
  2. 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程序。
  3. ComSpec env变量定义了由.bat.cmd脚本启动的程序。 (从WinNT开始,这默认为cmd.exe 。)
  4. cmd.exe向后兼容command.com
  5. cmd.exe设计的脚本可命名为.cmd以防止在Windows 9x上意外执行。 这个文件扩展名也可以追溯到OS / 2版本1.0和1987。

以下列出了command.com不支持的cmd.exe功能:

  • 长文件名(超过8.3格式)
  • 命令历史
  • Tab完成
  • 转义字符: ^ (用于: \ & | > < ^
  • 目录堆栈: PUSHD / POPD
  • 整数算术: SET /A i+=1
  • 搜索/替换/子字符串: SET %varname:expression%
  • 命令替换: FOR /F (之前存在,已被增强)
  • 函数: CALL :label

执行顺序:

如果脚本的两个.bat和.cmd版本(test.bat,test.cmd)位于相同的文件夹中,并且您运行的脚本没有扩展名(测试),则默认情况下脚本的.bat版本将运行,甚至在64位Windows 7上。执行顺序由PATHEXT环境变量控制。 有关更多详细信息,请参阅命令提示符执行文件的顺序

参考文献:

wikipedia: 比较命令外壳



这是我发现的一个区别: .cmd文件中需要 EnableDelayedExpansion
.bat文件的情况下,默认情况下是隐含的。 ( Windows 10

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

这适用于.bat但在.cmd文件的情况下始终可以found
line 2更改为以下内容使其按预期工作:

if %ERRORLEVEL% equ 0       (

最后对于.cmd文件,这可以正常工作:

setLocal EnableDelayedExpansion
...
if !ErrorLevel! equ 1       (
...

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

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

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

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


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

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

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


虽然更高版本的Windows有一个where命令,但您也可以使用环境变量修饰符在Windows XP中执行此操作,如下所示:

c:\> for %i in (cmd.exe) do @echo.   %~$PATH:i
   C:\WINDOWS\system32\cmd.exe

c:\> for %i in (python.exe) do @echo.   %~$PATH:i
   C:\Python25\python.exe

你不需要任何额外的工具,它不限于PATH因为你可以用你想使用的任何环境变量(当然是路径格式)。

而且,如果你想要一个可以处理PATHEXT中的所有扩展(就像Windows本身那样),那么这个技巧就是诀窍:

@echo off
setlocal enableextensions enabledelayedexpansion

:: Needs an argument.

if "x%1"=="x" (
    echo Usage: which ^<progName^>
    goto :end
)

:: First try the unadorned filenmame.

set fullspec=
call :find_it %1

:: Then try all adorned filenames in order.

set mypathext=!pathext!
:loop1
    :: Stop if found or out of extensions.

    if "x!mypathext!"=="x" goto :loop1end

    :: Get the next extension and try it.

    for /f "delims=;" %%j in ("!mypathext!") do set myext=%%j
    call :find_it %1!myext!

:: Remove the extension (not overly efficient but it works).

:loop2
    if not "x!myext!"=="x" (
        set myext=!myext:~1!
        set mypathext=!mypathext:~1!
        goto :loop2
    )
    if not "x!mypathext!"=="x" set mypathext=!mypathext:~1!

    goto :loop1
:loop1end

:end
endlocal
goto :eof

:: Function to find and print a file in the path.

:find_it
    for %%i in (%1) do set fullspec=%%~$PATH:i
    if not "x!fullspec!"=="x" @echo.   !fullspec!
    goto :eof

它实际上会返回所有可能性,但您可以轻松地针对特定搜索规则对其进行调整。





windows batch-file cmd