87

When typing cd.. without a space between cd and .. the Windows command prompt will happily switch to the parent folder. Is there an explanation for this behaviour? The command does not follow the standard format of command<space>arguments

Working but shouldn't?

Also, why does this not create consistent results?

echo..

psmears
  • 496
  • 3
  • 8
Jonas Köritz
  • 968
  • 1
  • 6
  • 18
  • 24
    The premise of your question appears to be broken. Can you provide any evidence for your claim that this is syntactically incorrect? – Lightness Races in Orbit Jun 06 '16 at 11:28
  • Added another example that raises questions for me... – Jonas Köritz Jun 06 '16 at 11:44
  • 13
    I don't think "commandarguments" has ever been the _standard_ format in cmd (or any of its predecesors); consider for example `dir/a` or the similar VMS syntax. – u1686_grawity Jun 06 '16 at 11:49
  • @JonasKöritz: Updated my answer. – Lightness Races in Orbit Jun 06 '16 at 12:05
  • 6
    cd is very special. You can type `cd c:\program files` without quotes and it still works – phuclv Jun 06 '16 at 13:09
  • 1
    also try `echo)`, `echo(`, `echo[`... and see – phuclv Jun 06 '16 at 13:11
  • 20
    Here is a very entertaining article which explains the quirks of the Windows shell logic, and what mayhem it can cause: http://thedailywtf.com/articles/The-Core-Launcher – vsz Jun 06 '16 at 14:08
  • @LưuVĩnhPhúc : +1 to your comment as these are my findings: **`echo(`**, seems to operate similar to **`echo.`**, as does using [, ], =, **`+`, `;`, `:`, `\\ `** (and, most surprisingly, **`echo/`**) by eliminating the first character after the word "echo". Trying `)`, `{`, `}`, `~`, `_`, or `-`** (or "back quote/tick") do not have the special effect, and expectedly complain that the command **`is not recognized as`** a valid command. **`echo^`** chops the first character, but **`echo^^`** and **`echo^^^`** error identically (showing only one ^ in output), while **`echo^^^^`** doesn't match. – TOOGAM Jun 07 '16 at 01:11
  • 1
    @vsz : The article was rather interesting. Although, it wasn't about the command line, but rather was about a CreateProcess() function, which is used by the Start\Run dialog box, according to comments (which referenced MSDN documentation). So, slightly different topic. – TOOGAM Jun 07 '16 at 01:14
  • 3
    Why does `cd..` work? Because Microsoft went through the trouble of explicitly making it work. `cd` is a command built into Windows' command interpreter, and Microsoft can make their interpreter do whatever they want. (As another example, `cd` also doesn't need quoting around directories with spaces in the name.) – jamesdlin Jun 08 '16 at 01:59
  • I'm pretty sure Raymond Chen ([The Old New Thing](https://blogs.msdn.microsoft.com/oldnewthing/)) wrote about this. Ofcourse I can't find it now. And that makes this comment pretty useless; except that maybe someone else's google-fu is better than mine and can dig up the post in question. – RobIII Jun 08 '16 at 13:42
  • Tangent: I remember an old utility program called `doskey` which, when installed, added variations on DOS command prompts. The main one I miss is adding dots to the `cd..` (or `cd ..`) command to substitute for higher directores. So, `cd...` was the equivalent of `cd ..\..` (or `cd..\..`), `cd....` was the equivalent of `cd ..\..\..` etc. I haven't had `doskey` in a donkey's age, but I still sometimes try to type those commands. – Wilson F Jun 08 '16 at 17:19
  • 1
    @vsz That's horrifying. TIL the Windows command interpreter _isn't even deterministic_. – matega Jun 08 '16 at 22:33
  • @vsz, that's a very good read, thanks. I didn't know Windows actually had any logic, especially its shell. :) – Andrea Lazzarotto Jun 09 '16 at 11:02
  • There is discussion at various points on this page that there isn't a defined syntax for these commands. In fact, there was. IBM's _Command Reference_ for OS/2 had the syntax for all of `cmd`'s commands given in the form of _railroad diagrams_. No, the IBM-specified syntax did not allow for non-spaces in these positions. [I have written on this subject](http://homepage.ntlworld.com./jonathan.deboynepollard/Softwares/cmd/guide/differences.html). [So has Rex Conn](https://groups.google.com/d/msg/comp.os.msdos.4dos/iQj0TBQEdMo/pMfKoLwGnP0J). – JdeBP Jun 10 '16 at 18:43

4 Answers4

107

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.

TOOGAM
  • 15,243
  • 4
  • 41
  • 58
  • "The behavior that you describe is consistent for all commands internal to the command line interpreter." `ipconfig` for example works too. – Jonas Köritz Jun 06 '16 at 19:48
  • @JonasKöritz : No. You can put a (forward) slash right after the command "**IPConfig**" and that will work, e.g. **`IPCONFIG/ALL`**. However, that's not what I was talking about. "*The behavior that you describe*" (in your question) was the behavior of placing a period right after the command name. If I type **`IPConfig.`** then I get an error about a command not being found. Similarly (although this is not related to the behavior you were describing), if I type **`IPCONFIG\ALL`** then I can run a custom **`.\IPCONFIG\ALL.BAT`** file that I made. So `/`'s are not treated like `.` or `\\` – TOOGAM Jun 06 '16 at 19:55
  • 1
    I will accept your answer to appreciate the work and research it took to create it! – Jonas Köritz Jun 06 '16 at 19:58
  • The ipconfig example makes perfect sense, though. You'd use `ipconfig.` *exactly* when you wanted to run `ipconfig.` instead of e.g. `ipconfig.exe` -that is, you specify that you're referencing a file with no extension, rather than a file with a "default" extension. So while it may appear inconsistent, it's an inconsistency in a case where the "consistent" behaviour would introduce ambiguities. It's not really different from `notepad myFile` (which creates/opens `myFile.txt`) and `notepad myFile.` (which creates/opens `myFile.`). – Luaan Jun 08 '16 at 13:02
  • 2
    @Calchas Simple test - try executing `copy.exe` or `copy.com` in cmd. It doesn't work - it's not an executable. – Luaan Jun 08 '16 at 13:03
  • 1
    @Luann : Regarding `ipconfig`, I disagree with your conclusion. This question is about what's typeed at the start of a command line. Windows/DOS identifies executables by filename extension, so you can't run a program called "ipconfig" without an extension (in Windows, unlike Unix which permits this). Regarding the next comment, I don't know who "Calchas" is. (When you specify an at sign, following is usually the first characters of a user that shows up elsewhere on the page.) I agree, running "`copy.exe`" will use the internal `copy` command (and pass `.exe`). (You can run `.\copy.exe`) – TOOGAM Jun 08 '16 at 15:02
41

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

Lightness Races in Orbit
  • 3,066
  • 1
  • 20
  • 29
  • 2
    I assumed this because it is unique to windows command line, bash for example will not allow you do do `cd..` – Jonas Köritz Jun 06 '16 at 11:41
  • 47
    @JonasKöritz: That's a completely different program on an entirely different operating system. My bicycle doesn't allow `cd..` either :) – Lightness Races in Orbit Jun 06 '16 at 11:43
  • 1
    As said the space is not mandatory, so `dir..` and others already mentioned also work. – David Balažic Jun 06 '16 at 12:05
  • 16
    @JonasKöritz: `alias cd..='cd ..'` – mouviciel Jun 06 '16 at 12:10
  • 2
    @Jonas: The reason here is also that command.com/cmd don't really have a generic command/argument parser as it wasn't necessary. Unlike on Unix, processes on Windows get just a string of arguments, not an array. Therefore, the command processor doesn't need to do any parsing beyond the process name (i.e. up to the first unquoted space). The built-in commands (`cd`, etc.) are even older and I'm not even sure the parser wasn't written in Assembler back then – the whole parsing of built-in commands is inconsistent and full of surprises, mostly because it's grown organically instead of specified. – Joey Jun 06 '16 at 12:41
  • @Joey Yup, exactly - the system evolved. When a bug started to be used by users, Microsoft had no choice but to support it in future versions. To be fair, the same thing is true of Unix - there's plenty of idiosyncracies that don't make any sense beyond the historical (e.g. "file names starting with `.` are invisible"). Unix was standardized long *after* most of those were already in place, and the standardization didn't really help much anyway - the differences between different POSIX-y systems are still huge, and they're quite incompatible unless you're very careful. – Luaan Jun 06 '16 at 13:33
  • @Luaan: What doesn't make sense about the leading-dot convention? It's extremely convenient. – Lightness Races in Orbit Jun 06 '16 at 14:10
  • 5
    @LightnessRacesinOrbit: Originally it was a shortcut of filtering out `.` and `..` which appear as directories in every other directory and as far as I know was never intended to catch more than that. I actually consider hidden-ness modelled as file attribute a cleaner design than having it implicitly follow from the file name. – Joey Jun 06 '16 at 14:20
  • 4
    @joey - I think the more relevant point is not that the DOS approach was simpler, it's that *DOS didn't allow `.` in filenames*, which meant it *couldn't be a part of a command name* therefore *must have been part of the argument*. Even if DOS had divided the command into arguments as Unix shells do, it would still place a `.` after the command into the first argument, because it would make no sense to put an invalid character into the command name. – Jules Jun 06 '16 at 15:00
  • to add to this, ipconfig/all works just like ipconfig /all, but arp-a does not work while arp/? does. Is my wording right if I say 'there's a difference between parameters and arguments' ? – Cand3r Jun 06 '16 at 15:03
  • @Cand3r: You'd be better off identifying that `-` counts as a character that may be part of a command name, thus it doesn't inherently make parsing proceed to the argument/parameter stage, unlike `/`. (Like if I live in "Paris,France" you know the comma is a delimiter between city and country; if I live in "Ashby-de-la-Zouch" that's just one word .. just the city. Even though neither example has even a single space character.) I'm not aware that there is a different name for `/abc` than for `-abc`, though. – Lightness Races in Orbit Jun 06 '16 at 15:12
  • Why do you say "`.` cannot be part of the command name"? Try this: `md .bat`, `echo echo batch > cd.bat`, `cd.bat`. You'll see "batch" echoed - you won't end up in the `.bat` folder. – nobody Jun 07 '16 at 00:27
  • @AndrewMedico: Hmm, granted! It must do some backtracking then. – Lightness Races in Orbit Jun 07 '16 at 13:35
  • +1 for We might only have consistency, inconsistently. – Mardoxx Jun 08 '16 at 13:19
  • To use words like "parse" and "token" in describing this cruft is very charitable. – Kaz Jun 09 '16 at 04:34
  • @Kaz: lol indeed. I feel dirty trying to describe this stuff in any sort of rigourous way. But, needs must... – Lightness Races in Orbit Jun 10 '16 at 11:33
18

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

Overmind
  • 9,924
  • 4
  • 25
  • 38
  • 8
    I guess the main issue is that the command cannot be "syntactically incorrect" because the syntax _is not formally specified anywhere_, so if the primary implementation (cmd.exe and/or MS-DOS) accepts it, then it has to be correct. – u1686_grawity Jun 06 '16 at 10:47
  • 3
    Also, CD is not a program, but an internal command. Similar to Echo which also is an internal command, it does not need to have a space for it to work. `echo.` works just as well, which will print an empty line. – LPChip Jun 06 '16 at 10:52
  • Well good old DOS times when people were digging into every OS file certainly helps with this sort of things. Very few thing of the good old days no longer work in regard to command line. Command.com was created to be able to read special characters after any given command. Just as a test, try "MD." and "MD..". Don't worry, it won't break anything. @LPChip - not like echo, since something like 'cdc' will not work, but "cd." will be interpreted. – Overmind Jun 06 '16 at 10:53
  • Why didn't they stick with command-space-arguments syntax? – Jonas Köritz Jun 06 '16 at 10:56
  • @JonasKöritz DOS was one of the first OSses. They probably wanted to type `cd..`. as quicker than `cd ..` Why they did it is something we can only guess. – LPChip Jun 06 '16 at 10:58
  • 2
    @Overmind echoe will not work either, so its the same with cd, echo, md, etc. – LPChip Jun 06 '16 at 10:59
  • Yes, LDChip, but echo.e will work, since '.' is special character. So the rule can be defined as 'no need for space if theres a special character involved'. – Overmind Jun 06 '16 at 11:02
  • @Overmind, wouldn't this result in `cd .` if any special character is ignored? – Jonas Köritz Jun 06 '16 at 11:24
  • 2
    @JonasKöritz , the `.` is not dropped but just a space is added. `md.test` and `md .test` both create the directory `.test`. Typing `cd.test` and `cd .test` will change into the directory `.test`. – daniel.heydebreck Jun 06 '16 at 11:35
  • 6
    @JonasKöritz: Because the syntax has never been command-space-arguments. – Lightness Races in Orbit Jun 06 '16 at 11:38
  • @LPChip First versions of DOS didn't even have `cd` - what's the point of a "change directory" command when you *don't have directories*? :) But most importantly, there was no ambiguity - you couldn't execute a program named `cd.`, since it wasn't an executable, and `cd..` wouldn't be a valid file name at all. Of course, those are perfectly both valid executable filenames *now*, so the modern `cmd` has to be a lot smarter to make sure things work as expected. – Luaan Jun 06 '16 at 13:38
11

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.

Jules
  • 431
  • 7
  • 16