Windows batch files: .bat vs .cmd?
Asked Answered
I

12

895

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?

Intended answered 29/9, 2008 at 14:39 Comment(2)
if i am not mistaken .ps1 files should be a windows Power Shell file. I could be wrong though.Antitoxic
.ps1 is a Windows PowerShell file which is an entirely different language from .bat/.cmd batch files.Umlaut
E
545

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.
Ellersick answered 29/9, 2008 at 14:41 Comment(10)
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.Spaceman
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!".Pianissimo
I think it is saying only those specific commands would do the different set/not set actions. Others will work like normalPachydermatous
I don't agree about setting the errorlevel.. But, maybe I don't understand (exactly) what you guys mean.. I always return a proper errorlevel from my batch files! If I execute a command that returns a negative errorlevel, such as dir c:\doesntexist, then execute a command that returns a success, such as dir "%temp% - the errorlevel is set appropriately.. See this: gist.github.com/kodybrown/7430acd13634c682ae75. I just tested this on Windows 10, but I've done this in 7/8/8.1 and I'm pretty certain that it worked on XP as well. (No idea if it worked on Vista! Who used that anyway!?)Andrel
I understand now. I updated my gist. Apparently, it doesn't (re)set the errorlevel when calling a set var=.. statement. Which is odd, because I assumed that was expected behavior. Arguments could be made for both. I'll stick with .bat files. :-)Andrel
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.Eubanks
The FTYPE command also clears the ERRORLEVEL to 0 only when executed by a .cmd script.Eubanks
I had no idea there was a behavioral difference; I thought the only difference was that it would be less likely that a .cmd file would get fed to command.com rather than cmd.exe, since presumably DOS doesn't search for them (by default) and Windows 9x doesn't have an association for them. The take-home being that you could justify skipping any "is this cmd.exe?" checks in .cmd, but not in .bat. (32-bit Windows still ships with the DOS compatibility, right?)Electrolyte
The quote doesn't say anything about resetting anything to zero, so I can't seem to figure out why that's the takeaway. The sentence ".BAT sets ERRORLEVEL only on errors" implies that .CMD would contrast with that by setting ERRORLEVEL even when there is no error. That means .BAT and .CMD would both set ERRORLEVEL when there is an error, but only .CMD would set ERRORLEVEL when there isn't.Polymyxin
Setting the errorlevel when there is no error (which is errorlevel 0) means setting errorlevel to 0 :)Marv
I
485

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

  1. command.com is the 16-bit command processor introduced in MS-DOS and was also used in the Win9x series of operating systems.
  2. 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.
  3. The ComSpec env variable defines which program is launched by .bat and .cmd scripts. (Starting with WinNT this defaults to cmd.exe.)
  4. cmd.exe is backward compatible with command.com.
  5. 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:

wikipedia: Comparison of command shells

Intended answered 29/9, 2008 at 14:39 Comment(15)
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.Maharanee
Hey Mike, if you have any specifics on command.com features that don't work on cmd.exe, I think it would be worth posting a separate answer on that.Intended
It's been so long since I worked on Win9x or DOS the only thing I can remember is that you could do something like "cd ..." to go up more than one directory level (hey, I said minor, didn't I?). However, see my edited answer for info about command.com's processing on NT.Maharanee
cmd.exe was introduced with NT 4.0 I believe, not windows 95.Ashford
Chris: see the current version of the Wikipedia article, esp. the comment by Mark Zbikowski at groups.google.com/group/…Weismann
Using command.com you can load ansi.sys to enable ANSI escape codes for coloring text. I'm not sure if you can load ansi.sys in cmd.exe.Tapestry
@molasses: You can't. With 64-bit systems it's a moot point now, though.Cause
No. cmd, and the new convention of .cmd as an extension for command script files specifically for cmd and not command, was introduced with OS/2 version 1.0 in 1987.Scandura
Aliases and history are a function of the console window (conhost.exe or csrss.exe), not cmd.exe. The history is integrated with the F7 pop-up box. Each attached program has its own history and aliases, managed by the console API or from the command line via doskey.Overburden
@MichaelBurr Perhaps you're referring to navigating up in the directory structure with the command CD ..\..\.. (would move up 3 levels)?Comeon
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.Vasyuta
@Aacini, concerning creation of empty files: rem also works in cmd, but only like this: rem/>empty.txt (instead of /, the following characters can be used well: . \ : + [ ]; note that ( ) do not work);Enright
Best answer. I want to point out the MAIN real world reason I would choose .cmd over .bat is to intentionally prevent a script from being run on 16-bit, but such a case is increasingly rare.Greenquist
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.Bise
The list of characters that can be escaped by ^ is wrong, a \ cannot be escaped: the following special characters can be escaped: &, |, >, <, ^, ", (, ); then you can also escape token separators like space, tab, ,, ;, =; you can even escape a line-feed character when there are two consecutive line-breaks; and you can even escape the ! when delayed expansion is enabled...Enright
S
180

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.

Sprawl answered 17/8, 2012 at 18:13 Comment(3)
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.Ceto
I really appreciate concise, pragmatic and clear answers over tons of walls of useless, university class-like answers.Suffragette
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!Jansenism
M
26

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.

Maharanee answered 29/9, 2008 at 14:41 Comment(4)
It may matter; as your link text mentions the differences are subtle.Sprawl
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.Hellen
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 ...Sag
@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.Maharanee
R
21

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.

Reconcile answered 7/7, 2012 at 22:47 Comment(1)
What OS was this? Something before XP?Alicyclic
A
21

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>
Armada answered 22/11, 2014 at 17:4 Comment(4)
It does that because test.bat is alphabetically before test.cmd. Windows does greedy completion.Fanniefannin
@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.Vasyuta
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.)Electrolyte
It's also worth noting that the current directory comes before other directories in the PATH environment variable regardless of extension.Azalea
J
13

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

Jukebox answered 5/2, 2014 at 14:46 Comment(5)
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.Butta
@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...Vasyuta
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.Butta
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.Tapetum
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).Dorothydorp
M
9

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

Maurey answered 29/9, 2008 at 14:47 Comment(1)
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.Sprawl
N
3

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.

Neri answered 29/9, 2008 at 17:40 Comment(0)
V
3

.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.

Velum answered 18/10, 2015 at 14:14 Comment(3)
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=1Velum
In .cmd files every command sets the errorlevel, in .bat files some commands leave the errorlevel unchanged, as described in the accepted answerGrimy
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.Velum
M
-1

The extension makes no difference.

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

Molarity answered 29/9, 2008 at 14:45 Comment(0)
G
-10

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.

Grimaud answered 3/4, 2010 at 20:22 Comment(8)
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?Intended
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 executeGrimy
You are perhaps thinking of .btm ("batch to memory") files as employed with JP Software's replacement command interpreters.Scandura
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.Lavone
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.Leventis
I think grey confused .cmd files with .com files, where were loaded into memory, but weren't batch files in any sense.Doctrine
Note: this behaviour, which affects the way FOR loops are evaluated, is one of the features controlled by command extensions, ENABLEEXTENSIONS and DISABLEEXTENSIONS.Healall
It may take a place when you run code under braces: ( ... ) In that particular case it keep reading the code lines until the closing brace ) even if the code execution inside braces block is paused by the pause command. To test that you can run Process Monitor and setup the filter for Operation: ReadFile + Process Name: cmd.exe. It keeps call ReadFile after the pause command and until the last closing brace ). At least it has the same behavior for .bat and .cmd on Windows 8.Adelric

© 2022 - 2024 — McMap. All rights reserved.