Why does "cd.." work in the Windows command line?

Solution 1:

As some of the other answers/comments note, the idea that there must be a space after the command is not correct. A well-known example is that you can type a forward slash after a command, without needing a space first.

However, there is another behavior which is a bit less understood, and allows the "cd.." that you are asking about. This behavior also allows for "cd\" to work.

The behavior that you describe is consistent for all commands internal to the command line interpreter. If you have certain symbols, including a period, forward slash, or backslash, then the prior characters are checked to see if they are a command that is internal to the "command line interpreter" shell (CMD.EXE or its predecessor COMMAND.COM).

This may be done before checking whether the word may refer to a file or subdirectory. That is true for the cd command. Tragically, when making a sample, I found that this does not happen with the copy command, so results are inconsistent: they are not necessarily the same with all internal commands. I didn't continue my search to also compare (much) other commands line del and dir, so I simply suggest being extremely careful if you try to rely on what happens without a space.

Now, the question also asked about the echo command: This is an unusual exception, in that I think echo. is fairly well-known by DOS experts. This probably was documented. The behavior, at least in Win7's CMD, is that if the command starts with "echo.", then the first period is ignored. So, "echo..hi" turns into output of ".hi". The reason for this is so that "echo." can be used to print a blank line. In contrast, with Unix, you can do this simply by running the "echo" command by itself. However, in DOS, running the "echo" command by itself will output the current "echo" setting. Similarly, DOS treats "Echo *Off*" and "Echo *On*" as special values that change the current echo setting. If you actually want to print the word "Off", then "Echo.Off" does the trick (at least with recent-enough versions of Microsoft's CMD command line interpreter.)

So, at least the echo command has a semi-reasonable explanation. As for the remaining commands, I used to think that internal commands had priority. However, when I tried to make some tests, I found that is actually rather inconsistent. I demonstrate this through some examples that I documented here.


Here are some examples. I did use an elevated command prompt, so that UAC wouldn't gripe about me writing to the root directory. This was done with Microsoft Windows 7's CMD.EXE. I suspect behaviors may be different with other versions, like COMMAND.COM from older MS-DOS versions, or software released by other companies (DR-DOS's COMMAND.COM).

(This answer is fairly long already, so I'm not including commands to clean up all of the mess I made on my filesystem. There's a tiny bit of clean-up, but not much.)

Here is an example that proves that the internal command creates precedence. (I also demonstrate the rather little-known ability to use a double colon to effectively be a comment, which also works well in batch files. Technically, in batch files, it gets processed as a label which cannot be reached by GOTO, and ends up being faster than the REM command.)

C:\something> md cd
C:\something> echo echo subdir >> cd\a.bat
C:\something> md \a
C:\something> .\cd\a.bat
subdir

C:\something> :: That ran from the subdir
C:\something> cd\a
C:\a> :: That changed my current directory, so cd took precedence

Update: Upon further experimentation, I found that the internal cd command only takes precedence over the filesystem if the specified directory does not include a period. So if you have a directory named "a.bat", then you can run "**cd\a.bat**" and the batch file will run.

This exploration of less common behavior (since most directories probably do not have periods in them) led me to update my findings. It turns out that the cd command is actually behaving more similar to the copy command than I initially thought.

Although I initially thought the cd and copy commands were behaving different, I now figured out that is because of the pattern of the names I was providing. Still, I reviewed my earlier results, and determined that my earlier documented tests do help to show some of the difference between what happens when a name includes a period and an extension, and when it doesn't. So, I'm still including my older findings below (mostly unchanged, but with some very minor updates so what I say is accurate).

Here is an example demonstrating copy, with a full path, does not use the same precedence (favoring the internal command) as cd when no extension is used:

C:\something> echo echo root >> \try.bat
C:\something> md copy
C:\something> echo echo subdirectory >> copy\try.bat
C:\something> .\copy\try.bat runs from the subdirectory
subdirectory

C:\something> copy\try.bat
subdirectory

C:\something> :: Huh? Why didn't that override and run from root?
C:\something> :: Apparently, the internal copy command didn't have priority over the check for a subdirectory and full filename (even though the internal cd command did take priority, when the directory had no extension)
C:\something> ::
C:\something> :: Another test: I can add useless periods at the end
C:\something> .\copy..\try.bat
subdirectory

C:\something> :: Okay, great. But then this will not check the subdirectory:
C:\something> copy..\try.bat
        1 file(s) copied.

C:\something> ::That ran the internal copy command

My early findings indicated that these results demonstrate that the command line shell gives priority:

  • to the filesystem (instead of the internal copy command) when specifying a backslash right after the name of the internal command
  • to the internal cd command (instead of the filesystem) when specifying a backslash right after the name of the internal command.
  • to the internal copy command (instead of the filesystem) when specifying a period right after the name of the internal command.

This clearly demonstrates that the behavior is not consistent between the copy command (with a full filename including an extension) and the cd command (without an extension as part of the directory name). When using a backslash, the copy command (with the full filename extension) will check the filesystem first, but the cd command won't (if the directory does not contain an extension).

(Update: At first, I thought the inconsistency was based on different behavior between the programs. Later, I discovered that the inconsistency did exist, but was caused more from the provided parameters.)

Actually, even those bullet points are not entirely accurate, even though I did just seem to demonstrate every individual thing I just said. The problem is, that list of bullet points are not precise enough to be completely accurate. (I left things imprecise so that those bullet points could be compared relatively easily, and checked relatively easily.)

However, to be more accurate, the first bullet point should point out that the command line shell gives priority:

  • to the filesystem (instead of the internal copy command) when specifying a backslash, and then the remainder of the full path, right after the name of the internal command

The following will demonstrate why I'm making that distinction:

C:\elsewhere> echo UAC elevation needed for this line >> \needext
C:\elsewhere> echo UAC elevation needed for this line >> \needext.bat
C:\elsewhere> md.\copy
C:\elsewhere> echo @Echo subdir >> copy\needext.bat
C:\elsewhere> .\copy\needext
subdir

C:\elsewhere> copy\needext.bat
subdir

C:\elsewhere> copy\needext
        1 file(s) copied.

C:\elsewhere> :: UAC also needed for the next lines
C:\elsewhere> del \needext
C:\elsewhere> del \needext.bat

(Note that the last copy command looked for the file called \needext, because the internal copy command was used. The file \needext.bat was only created to help easily show that it never got used by the command lines that included the word copy.)

At this point, I established some inconsistency (with the behavior of the copy command) when a backslash is used...

Next I will demonstrate that there is some consistency between these commands. (So, there is consistency... um... sometimes. We might only have consistency, inconsistently.) What I will show next is that the cd command does behave rather like the copy command when a period is used. The copy command uses the internal command, and so does the cd command.

C:\something> md.\yetmore

C:\something> cd.\yetmore

C:\something\yetmore> md.\md
C:\something\yetmore> echo echo subdir >> md\test.bat
C:\something\yetmore> .\md.\test
subdir

C:\something\yetmore> md.\test

C:\something\yetmore> md.\test
A subdirectory or file .\test already exists.

C:\something\yetmore> :: That error shows we ran the internal command.
C:\something\yetmore> md..\test
C:\something\yetmore> md.\cd
C:\something\yetmore> copy.\md cd
.\md\test.bat
        1 file(s) copied.

C:\something\yetmore> .\cd.\test
subdir

C:\something\yetmore> cd.\test
C:\something\yetmore\test> ::the internal command worked with one period
C:\something\yetmore\test> cd..
C:\something\yetmore> .\cd..\test
subdir

C:\something\yetmore> cd..\test
C:\something\test> :: internal command also took priority when two periods are used

So, during the initial test session which mostly focused on the cd and copy commands (with some additional usage of md and a bit of del), the only time that we really had the filesystem take priority was with the copy command, and then the filesystem was only taking priority when using the full path.

After subsequent review, I found that the cd command also gave the filesystem priority when using an extension. At least this means the internal commands are being treated a bit more consistent with each other. However, it also means that we get different behavior based on the names of the filesystem objects (the files or directories). That seems like the behavior is using some really, really obscure internal logic. Therefore, counting on this behavior to work across different operating systems is something I would probably consider to be unsafe to do.

Solution 2:

You assume that a command name and its arguments must be separated by a space, specifically, but this is not true. As long as the invocation can be unambiguously interpreted, the invocation is valid.

In this case, the first argument begins with . and . cannot be part of the command name, so cd and .. are simply parsed as two separate tokens.

Usually, your first argument will start with an alphabetic character (e.g. the beginning of a path), so it'll "bleed" into your command name and cause an error… but that is not a syntax problem. It's a semantic one.

You can see the same effect at work with other commands, including echo:

echo...
..

In this case, we get only two periods because the echo command itself has a special rule, so that the following:

echo .

or, by extension, this:

echo.

outputs only an empty line. It's a convenience. Apparently it's been implemented by ignoring a leading period in the argument.

Hey, this is DOS/Batch. You want sanity? :D

Solution 3:

The cd..command is correct and it was defined like that in the original command interpreter command.com which later was named cmd.exe.

The command interpreter knows how to process cd.., because . is a special character, just like \.

Solution 4:

It's a backwards compatibility hack.

The command line interpreter is designed to be backwards compatible with commands from the original MSDOS command interpreter, which was designed to be backwards compatible with the CP/M command interpreter. Neither CP/M nor MSDOS allowed a . in a filename (it was interpreted as a separator between two parts of the filename, the base name and the extension). This meant that (at least for early versions of DOS), the command interpreter could identify that if it reached a '.' (or indeed any other character that was illegal in a filename) it passed the end of the command name and was into the command arguments. This was quite commonly used in both DOS and CP/M -- for example, dir/w was a very common command, equivalent to dir /w meaning to list files in a horizontal format.

Nowadays, '.' can appear in filenames. This causes some complications in how to parse commands, but the shell still identifies a . that is not part of an exact filename as being the beginning of arguments. This is necessary largely because millions of users have grown used to typing cd.. or have large numbers of batch files containing that or echo. or any number of other similar commands.