795

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?

Ross Ridge
  • 35,323
  • 6
  • 64
  • 105
Chris Noe
  • 33,647
  • 22
  • 66
  • 90

13 Answers13

487

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.
Jean-François Corbett
  • 34,562
  • 26
  • 126
  • 176
Ben Hoffstein
  • 98,117
  • 8
  • 99
  • 119
  • 6
    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. – djangofan Jul 01 '13 at 16:22
  • 37
    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!". – MadScientist Jul 10 '13 at 15:37
  • 6
    I think it is saying only those specific commands would do the different set/not set actions. Others will work like normal – PsychoData Feb 04 '14 at 22:41
  • 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: https://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!?) – kodybrown Aug 18 '15 at 13:25
  • 2
    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. :-) – kodybrown Aug 18 '15 at 13:40
  • 2
    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. – dbenham Jan 22 '16 at 17:32
  • 1
    The FTYPE command also clears the ERRORLEVEL to 0 only when executed by a `.cmd` script. – dbenham Jan 23 '16 at 19:25
  • 1
    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?) – SamB May 20 '17 at 18:29
  • What makes it significant? – neverMind9 May 26 '18 at 14:13
440

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

Community
  • 1
  • 1
Chris Noe
  • 33,647
  • 22
  • 66
  • 90
  • 6
    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. – Michael Burr Sep 29 '08 at 23:01
  • 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. – Chris Noe Sep 30 '08 at 00:02
  • 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. – Michael Burr Sep 30 '08 at 05:00
  • 7
    cmd.exe was introduced with NT 4.0 I believe, not windows 95. – FlySwat Oct 01 '08 at 01:53
  • 2
    Chris: see the current version of the Wikipedia article, esp. the comment by Mark Zbikowski at http://groups.google.com/group/microsoft.public.win2000.cmdprompt.admin/msg/ad9066638815812c – Mark May 04 '09 at 09:01
  • 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. – molasses Oct 01 '09 at 05:14
  • @molasses: You can't. With 64-bit systems it's a moot point now, though. – Joey Apr 15 '10 at 22:36
  • 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. – JdeBP Jan 02 '12 at 12:08
  • 1
    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](http://msdn.microsoft.com/en-us/library/ms682073) or from the command line via [doskey](http://technet.microsoft.com/en-us/library/bb490894.aspx). – Eryk Sun Apr 12 '14 at 07:07
  • @MichaelBurr Perhaps you're referring to navigating up in the directory structure with the command `CD ..\..\..` (would move up 3 levels)? – I say Reinstate Monica Oct 01 '14 at 02:01
  • 4
    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. – Aacini May 24 '15 at 17:39
  • @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); – aschipfl Nov 26 '15 at 23:40
  • 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. – Richard Smith Jun 11 '17 at 04:50
  • 4
    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. – Stewart Nov 07 '18 at 14:45
  • 1
    The list of characters that can be escaped by `^` is wrong, a `\ `cannot be escaped: the following special characters can be escaped: `&`, `|`, `>`, ` – aschipfl May 14 '20 at 14:22
115

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.

Gringo Suave
  • 25,443
  • 6
  • 77
  • 69
  • 7
    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. – Oliver Feb 24 '14 at 14:04
  • 22
    I really appreciate concise, pragmatic and clear answers over tons of walls of useless, university class-like answers. – Liquid Core Oct 16 '18 at 07:19
  • 11
    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! – Eureka May 06 '19 at 10:26
24

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.

Michael Burr
  • 311,791
  • 49
  • 497
  • 724
  • 5
    It may matter; as your link text mentions the differences are subtle. – Gringo Suave Feb 20 '13 at 03:11
  • 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. – phd443322 Jun 18 '14 at 12:45
  • 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 Apr 16 '15 at 09:12
  • @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. – Michael Burr Apr 16 '15 at 17:45
17

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.

David Gray
  • 171
  • 1
  • 2
16

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>
tvCa
  • 724
  • 6
  • 12
  • It does that because test.bat is alphabetically before test.cmd. Windows does greedy completion. – David Apr 03 '15 at 18:55
  • 34
    @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. – Aacini May 24 '15 at 17:12
  • 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.) – SamB May 20 '17 at 19:01
  • 4
    It's also worth noting that the current directory comes before other directories in the `PATH` environment variable regardless of extension. – Turkeyphant Jun 10 '19 at 22:59
15

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

Rob at TVSeries.com
  • 2,144
  • 1
  • 18
  • 13
  • 2
    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. – Jon Davis Apr 03 '15 at 20:36
  • 3
    @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... – Aacini May 24 '15 at 17:22
  • 1
    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. – Jon Davis May 25 '15 at 21:22
  • 6
    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. – Ricardo Zorio Sep 25 '15 at 19:50
8

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

Lorenzo Boccaccia
  • 5,707
  • 2
  • 17
  • 27
  • 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. – Gringo Suave Feb 20 '13 at 03:17
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.

Patrick Cuff
  • 26,370
  • 11
  • 63
  • 93
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.

Mofi
  • 38,783
  • 14
  • 62
  • 115
zask
  • 181
  • 1
  • 5
  • 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` – zask Jan 25 '16 at 17:28
  • 5
    In .cmd files every command sets the errorlevel, in .bat files some commands leave the errorlevel unchanged, as described in the accepted answer – jeb Jan 25 '16 at 17:46
  • 1
    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. – zask Jan 26 '16 at 03:53
1

The extension makes no difference.

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

Waldo
  • 226
  • 1
  • 2
1

Slightly off topic, but have you considered Windows Scripting Host? You might find it nicer.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Marcin
  • 44,601
  • 17
  • 110
  • 191
  • 13
    For that matter, PowerShell, which deprecates WSH/cscript.exe. – Jon Davis Jul 03 '10 at 20:40
  • 3
    @stimpy77 True, although powershell seems pretty terrible to me. – Marcin Sep 16 '12 at 18:39
  • 2
    I find WSH much worse. I suppose it all depends on what we are measuring for "terrible". PowerShell has atrocious startup time. Everything about it is absolutely wonderful IMO. – Jon Davis Sep 18 '12 at 22:55
  • Excuse the formatting, but to speed up PSH startup time, try running: Set-Alias ngen @( dir (join-path ${env:\windir} "Microsoft.NET\Framework") ngen.exe -recurse | sort -descending lastwritetime )[0].fullName [NEW LINE HERE] [appdomain]::currentdomain.getassemblies() | %{ngen $_.location} – mjbnz Mar 25 '13 at 20:51
  • 1
    Completely off-topic. – HappyDog Jul 11 '19 at 09:19
-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.

grey
  • 13
  • 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? – Chris Noe Apr 05 '10 at 21:27
  • 24
    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 – jeb Nov 06 '10 at 00:01
  • 4
    You are perhaps thinking of [`.btm` ("batch to memory") files as employed with JP Software's replacement command interpreters](http://jpsoft.com./help/batchtype.htm). – JdeBP Jan 02 '12 at 12:13
  • 1
    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. –  Mar 03 '12 at 03:06
  • 2
    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`. – venimus Jun 14 '12 at 08:29
  • I think grey confused .cmd files with .com files, where *were* loaded into memory, but weren't batch files in any sense. – nitind Jun 25 '14 at 17:18