ChatGPT解决这个技术问题 Extra ChatGPT

Windows batch files: .bat vs .cmd?

As I understand it, .bat is the old 16-bit naming convention, and .cmd is for 32-bit Windows, i.e., starting with NT. But I continue to see .bat files everywhere, and they seem to work exactly the same using either suffix. Assuming that my code will never need to run on anything older than NT, does it really matter which way I name my batch files, or is there some gotcha awaiting me by using the wrong suffix?

Just to add to the confusion we now have .ps1 files as well.
if i am not mistaken .ps1 files should be a windows Power Shell file. I could be wrong though.
.ps1 is a Windows PowerShell file which is an entirely different language from .bat/.cmd batch files.

J
Jean-François Corbett

From this news group posting by Mark Zbikowski himself:

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.

In other words, if ERRORLEVEL is set to non-0 and then you run one of those commands, the resulting ERRORLEVEL will be:

left alone at its non-0 value in a .bat file

reset to 0 in a .cmd file.


Does that imply that using a .bat script would not return a ERRORLEVEL 0 value on a success? If that is true, I never noticed it.
I think it means that if ERRORLEVEL was set to non-0, then you run one of those commands, it will be left alone (non-0) in a .bat file but reset to 0 in a .cmd file. But, Windows being what it is, it's quite possible it actually causes a disembodied voice to tell you, in Pig Latin, "reset ERRORLEVEL yourself if you care so much!".
I think it is saying only those specific commands would do the different set/not set actions. Others will work like normal
Note - The APPEND command has been replaced with the undocumented DPATH command, although DPATH /? still lists the command as APPEND. Also, the Wiki article has since been mostly corrected, except it does not list DPATH.
The FTYPE command also clears the ERRORLEVEL to 0 only when executed by a .cmd script.
1
19 revs, 10 users 79%

Here is a compilation of verified information from the various answers and cited references in this thread:

command.com is the 16-bit command processor introduced in MS-DOS and was also used in the Win9x series of operating systems. cmd.exe is the 32-bit command processor in Windows NT (64-bit Windows OSes also have a 64-bit version). cmd.exe was never part of Windows 9x. It originated in OS/2 version 1.0, and the OS/2 version of cmd began 16-bit (but was nonetheless a fully fledged protected mode program with commands like start). Windows NT inherited cmd from OS/2, but Windows NT's Win32 version started off 32-bit. Although OS/2 went 32-bit in 1992, its cmd remained a 16-bit OS/2 1.x program. The ComSpec env variable defines which program is launched by .bat and .cmd scripts. (Starting with WinNT this defaults to cmd.exe.) cmd.exe is backward compatible with command.com. A script that is designed for cmd.exe can be named .cmd to prevent accidental execution on Windows 9x. This filename extension also dates back to OS/2 version 1.0 and 1987.

Here is a list of cmd.exe features that are not supported by command.com:

Long filenames (exceeding the 8.3 format)

Command history

Tab completion

Escape character: ^ (Use for: \ & | > < ^)

Directory stack: PUSHD/POPD

Integer arithmetic: SET /A i+=1

Search/Replace/Substring: SET %varname:expression%

Command substitution: FOR /F (existed before, has been enhanced)

Functions: CALL :label

Order of Execution:

If both .bat and .cmd versions of a script (test.bat, test.cmd) are in the same folder and you run the script without the extension (test), by default the .bat version of the script will run, even on 64-bit Windows 7. The order of execution is controlled by the PATHEXT environment variable. See Order in which Command Prompt executes files for more details.

References:

cmd.exe

command.com

wikipedia: Comparison of command shells


Several minor points: 1) .bat does not necessarily invoke command.com - apparently when command.com is invoked is a bit of a complex mystery; 2) command.com was introduced with MS-DOS; 3) cmd.exe can run most command.com scripts, but there are a few minor command.com things that don't work in cmd.
cmd.exe was introduced with NT 4.0 I believe, not windows 95.
Chris: see the current version of the Wikipedia article, esp. the comment by Mark Zbikowski at groups.google.com/group/…
Just to add some info about this matter: dir filename is the same as dir filename.* in command.com; the wild-card is required in cmd.exe. In command.com rem Create an empty file > empty.txt works; not in cmd.exe.
Only a little bit of this seems to be relevant to the OP's question, which is about the difference between .bat and .cmd, not the difference between command.com and cmd.exe. As I read it, the question is about the difference between a .bat file and a .cmd file, all other things being equal.
G
Gringo Suave

These answers are a bit too long and focused on interactive use. The important differences for scripting are:

.cmd prevents inadvertent execution on non-NT systems.

.cmd enables built-in commands to change Errorlevel to 0 on success.

Not that exciting, eh?

There used to be a number of additional features enabled in .cmd files, called Command Extensions. However, they are now enabled by default for both .bat and .cmd files under Windows 2000 and later.

Bottom line: in 2012 and beyond, I recommend using .cmd exclusively.


IMO, that's the main point. You use .cmd as extension for newer scripts when you want to make sure they are not exececuted on older 16-bit OSs, or if you are not sure they will work.
I really appreciate concise, pragmatic and clear answers over tons of walls of useless, university class-like answers.
I am university professor and I agree with @Liquid Core ! Concise, pragmatic, clear answers are how we learn (when we don't know something yet). Then, somehow, once we understand it, we feel the urge to explain it in an abstract and incomprehensible way. Weird. Good observation!
M
Michael Burr

No - it doesn't matter in the slightest. On NT the .bat and .cmd extension both cause the cmd.exe processor to process the file in exactly the same way.

Additional interesting information about command.com vs. cmd.exe on WinNT-class systems from MS TechNet (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.


It may matter; as your link text mentions the differences are subtle.
You can force command.com to execute a dos command by specifing it on the command line. See command /c ver versus starting command.com and typing ver.
Name matters :D Saw lot of .bat from guys are from the past! Use .cmd! Also can't believe that NT is still used today ...
@hfrmobile: When I mentioned 'NT' I meant basically all Windows versions that we're based on NT (and not 9x). So essentially NT, Win2k, and all versions of Windows for the desktop or server since XP. And the name of the file may give insight into the mindset and coding style of the person who wrote the file, but as far as the interpreter there's no difference.
D
David Gray

RE: Apparently when command.com is invoked is a bit of a complex mystery;

Several months ago, during the course of a project, we had to figure out why some programs that we wanted to run under CMD.EXE were, in fact, running under COMMAND.COM. The "program" in question was a very old .BAT file, that still runs daily.

We discovered that the reason the batch file ran under COMMAND.COM is that it was being started from a .PIF file (also ancient). Since the special memory configuration settings available only through a PIF have become irrelevant, we replaced it with a conventional desktop shortcut.

The same batch file, launched from the shortcut, runs in CMD.EXE. When you think about it, this makes sense. The reason that it took us so long to figure it out was partially due to the fact that we had forgotten that its item in the startup group was a PIF, because it had been in production since 1998.


What OS was this? Something before XP?
t
tvCa

Still, on Windows 7, BAT files have also this difference : If you ever create files TEST.BAT and TEST.CMD in the same directory, and you run TEST in that directory, it'll run the BAT file.

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>

It does that because test.bat is alphabetically before test.cmd. Windows does greedy completion.
@David: Not true. This happens because in PATHEXT variable the .BAT extension is placed before .CMD one (as shown in this answer). If you modify this order in PATHEXT, the test.cmd would be executed instead.
Hmm, I was hoping they were in the other order; I guess MS must have discovered (or assumed) that some existing software shipped .CMD files and .BAT files with the same basename, where the .CMD files were of course not intended as input for the (not-yet-shipped) cmd.exe, but could have been any number of other things: commands for some other shell, a configuration script read by the application, or some sort of application binary, for example. (At least, that's my understanding of the usual way MS end up with seemingly sub-optimal behavior.)
It's also worth noting that the current directory comes before other directories in the PATH environment variable regardless of extension.
R
Rob at TVSeries.com

Since the original post was regarding the consequences of using the .bat or .cmd suffix, not necessarily the commands inside the file...

One other difference between .bat and .cmd is that if two files exist with the same file name and both those extensions, then:

entering filename or filename.bat at the command line will run the .bat file

to run the .cmd file, you have to enter filename.cmd


Eh? If I put a cmd file in my dir I don't have to specify the file extension to invoke it. Example: echo notepad.exe %* > np.cmd Then if I just type "np mytextfilename.txt" it will bring up notepad. I don't have to type "np.cmd" to invoke it.
@stimpy77: This is true if np.cmd is the only file with that name, but "if two files exist with the same file name and both those extensions", then the only way to execute the .cmd one is including its extension...
This is a necessity of resolving ambiguity for any shell, nothing to do with technical differences between .cmd vs .bat. It's probably because filename.bat precedes filename.cmd alphabetically.
It actually depends on the PATHEXT environment variable. The order in wich the extensions appears there is the order of precedence if an extension is not specified. It is also worth mentioning that it's not necessary to specify an extension for the files wich its extension appears in the env variable.
I note this answer is from 2014 - is it still correct?... (I've never had to specifically add .cmd in order to run MyScript.cmd - AFAIK C:\> MyScript works fine (for .cmd or .bat files).
L
Lorenzo Boccaccia

everything working in a batch should work in a cmd; cmd provides some extensions for controlling the environment. also, cmd is executed by in new cmd interpreter and thus should be faster (not noticeable on short files) and stabler as bat runs under the NTVDM emulated 16bit environment


Shouldn't make any difference in speed. .bat doesn't run under DOS in NT. A VDM is only started if a program needs it, and isn't even supported in 64bit Windows, though I believe .bat is.
M
Mofi

.cmd and .bat file execution is different because in a .cmd errorlevel variable it can change on a command that is affected by command extensions. That's about it really.


Of coarse ^.^ There are differences in the command language used for each (.bat files get a compatibility version). Some of these can be illustrated by this script from over here: @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
In .cmd files every command sets the errorlevel, in .bat files some commands leave the errorlevel unchanged, as described in the accepted answer
BAT was created to interact with COMMAND.COM, the command interpreter of DOS. Microsoft adopted most of the DOS commands into their new interpreter named CMD. EXE. CMD was created to interface with CMD.EXE and it breaks compatibility with COMMAND.COM. mainly known for how they handle the errorlevel variable. When using BAT, this variable is only changed once an actual error occurs and no change in state occurs when the each command executes successfully. This is not true for CMD as the errorlevel variable would still change state even if no errors occur.
P
Patrick Cuff

I believe if you change the value of the ComSpec environment variable to %SystemRoot%system32\cmd.exe(CMD) then it doesn't matter if the file extension is .BAT or .CMD. I'm not sure, but this may even be the default for WinXP and above.


W
Waldo

The extension makes no difference.

There are slight differences between COMMAND.COM handling the file vs CMD.EXE.


g
grey

a difference:

.cmd files are loaded into memory before being executed. .bat files execute a line, read the next line, execute that line...

you can come across this when you execute a script file and then edit it before it's done executing. bat files will be messed up by this, but cmd files won't.


As has been established, the ComSpec env variable defines which program is launched, are you essentially saying that command.com reads the file a line at a time, while cmd.exe pre-loads the file into memory? Can you cite a reference on this?
It's wrong for Vista and XP, both file types are read line by line. If you pause the .cmd or .bat file and edit it, the new code will be execute
One could debate whether it's line by line, because if you pause execution in the middle of the command file and add a character at the beginning, upon resuming the parser will be off by one character, possibly throwing off the rest of your script.
You should not debate .bat and .cmd does not differ in that manner. Both are always read line by line. You can test it if you don't believe. Make a batch file that have echo 1&pause then execute it. You will see 1 and Press any key to continue.... While paused add a new line echo 2&pause with external editor. Press a key. You will see 2 and Press any key to continue.... You can even try adding echo 3&pause in the beginning. When you press a key after that again you will see 2.