I've occasionally thought on the difference between cmd and bat, and from an execution point of view I didn’t think there was any. But it turns out a few commands can modify the execution path of batch files, because they modify the errorlevel differently based on whether they were executed as a .bat or .cmd.
The comment that I did find from Microsoft (the source was MZ according to the signature block!)
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.
If you save the text below as test.bat and test.cmd, and then run each from a command prompt, you see two different results. Note that command extensions are enabled by default on XP, a requirement for this behavioural difference.
I saw several references to bat running under 16-bit VDM and cmd running under 32-bit when executed from a shortcut, however I couldn’t reproduce this on XP SP2.
In addition, apparently 9x days and before there was only bat? And then with NT CMD was introduced, and running the same .bat file on 9x and NT definitely had different results, so having two different extensions made it less likely to accidently run a cmd written for NT on a 9x box if you were interoperating between the two. This sounds plausible, but I can't remember those sorts of details that far back.
I hope this doesn’t excite anyone.
:: :: When called from a cmd, 'set' resets errorlevel, whereas when called from a bat the errorlevel from the previous command is returned. :: The four examples below show this in different ways, two calling a subroutine, and two using a single line. :: :: :test generates an error by find without any parameters (2) :: The set command then clears errorlevel when run as a .cmd file, but when run as a .bat, the previous errorlevel is returned :: :: Delayed environment variable expansion is enabled to allow showing ERRORLEVEL, but the same result occurrs if you use don't use delayed expansion (you just can't see the errorlevel) :: Therefore the single line below with delayed expansion shows the difference in return errorlevel, but the call to the label allows the if..then..else to also show the same results :: :: The last example uses concatenated commands, with the final command checking errorlevel and using if..else to report the difference :: :: && - If :: || - Else :: :: Comment from msft: :: 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. @echo off ::setlocal ENABLEEXTENSIONS setlocal ENABLEDELAYEDEXPANSION :: Call test, if successful echo cmd, else echo bat call :test && echo cmd || echo bat :: Call test, if successful echo cmd with delayed expansion of errorlevel, else echo bat call :test && echo cmd error: !errorlevel! || echo bat error: !errorlevel! :: Generate the error, clear the error, echo the delayed expansion of errorlevel find 2>nul & set test=test && echo Single-line error: !errorlevel! :: Generate the error, clear the error, if errorlevel 1 echo BAT, else echo CMD find 2>nul & set test=test & if errorlevel 1 (echo Run from BAT error) else (echo Run from CMD no error) goto :EOF :test :: Generate an error find 2>nul echo :test %errorlevel% :: Set a variable - when called with .cmd the errorlevel is reset set test=test echo :test %errorlevel% ::
Wayne's World of IT (WWoIT), Copyright 2008 Wayne Martin.