0

On Windows/DOS terminals a cd.. works well.

On Linux terminals the dots from the cd command have to be separated. I'd like to know how/why is this necessary for the parser to work. If no space is added then the command is not understood.

This works well

 cd ..

This does not work

cd..

Probably the regExp or whatever is parsing the commands is not including the dot as a possible character immediately after the command.

  • 1
    Same as the difference between my-random-command and my-random-command.. – muru Jul 8 at 15:18
  • 3
    I can’t post an answer, since the question is closed, so I’ll add this.  Apparently CMD looks at the first word on the command line, up to the last dot (or group of dots), and if that substring is a builtin command, it interprets it as that builtin command.  So cd.., dir.., type..\filename.txt and copy..\filename newname all act like there was a space before the first dot.  cls. and pause. ignore the dot, and echo.. acts like echo . [sic]. … (Cont’d) – G-Man Jul 8 at 22:41
  • 2
    (Cont’d) …  But this works only for builtins; for example, calc.. and find.. get the “… is not recognized as an internal or external command, operable program or batch file.” error.  So, for fun, if you have a program called abcd.efg.exe, you can run it by typing abcd.efg.  But if it’s called cd.efg.exe, then cd.efg fails, because it’s parsed as cd .efg.  You would have to type cd.efg.exe. – G-Man Jul 8 at 22:42
  • 4
    The larger (and more Unix-centric) answer — which nobody else has offered yet?! — is that Unix shells treat a lot of non-alphanumeric characters (e.g., @_+-{}:,./~) as if they were letters, so you could have commands called a@, b_, c+, d-, etc.  So when the shell sees cd.., it treats it as a four-letter word, no different from cdef or cd56, and so it looks for a command called cd...  It doesn’t break it into two words just because d is a letter and . isn’t (the way CMD does). – G-Man Jul 9 at 0:50
  • 1
    @G-Man Reopened. – Kusalananda Jul 17 at 7:06
7

The normal syntax is cd ... The Windows command interpreter is a bit more flexible and accepts cd.. as well.

When you use cd.. the shell tries to find a command or program named exactly cd..

To make your bash accept the command cd.. you can define an alias:

alias cd..="cd .."
  • 1
    or easier shopt -s autocd, and then type .. – pLumo Jul 8 at 15:24
  • iirc, windows also lets you do cd... instead of cd ../.. it takes a second to get used to that when making the windows to linux switch. – jhufford Jul 8 at 22:13
  • @jhufford: Hmm; what version of Windows are you using?  In Windows 7, cd... and cd ... do nothing. – G-Man Jul 8 at 22:19
  • 1
    computerhope.com/cdhlp.htm says that you can do cd... on Win95 and later, so maybe my recollection wasn't completely wrong. I guess I don't know to what versions that applies. – jhufford Jul 8 at 23:13
  • 1
    The Windows command interpreter is a bit more flexible and consequently not compatible with POSIX. – Isaac Jul 17 at 22:18
6

There is no real difference. The Windows CMD shell decided to accommodate the typo, whereas Linux's shells are more strict about separating the command or program (in this case the shell's built-in cd) from the argument.

  • 1
    How do you know they "decided to accommodate the typo"? How do you know they even considered it a typo to begin with, instead of just deciding to define the command or the parsing in a different way? – ilkkachu Jul 16 at 15:16
  • @ilkkachu Whoever they are decided to accept cd.. as a command equivalent to the pre-existing Unix command cd ... Without knowing who the primary actors were we really cannot discern their motives. We do know that a pre-existing command was modified and accepted as valid in the Windows environment. – doneal24 Jul 17 at 21:59
  • @doneal24, well, I think the fact that you had to explicitly mention Unix command is rather relevant here. It's not like DOS was directly based on Unix, and the command line is different enough that I wouldn't assume they had the same goals or definitions as Unixes to begin with. Now, if we looked at how CP/M or such did it, and why, that just might be interesting. – ilkkachu Jul 18 at 6:03
  • @ilkkachu Looking at CP/M might not return much help. CP/M 2.2 did not support subdirectories, hence no need for a cd command. – doneal24 Jul 18 at 12:35
  • @doneal24, ah, right. – ilkkachu Jul 18 at 16:26
3

Why doesn’t cd.. work in Unix & Linux?

Unix shells treat a lot of non-alphanumeric characters (e.g., @_+-{}:,./~) as if they were letters, so you could have commands called a@, b_, c+, d-, etc.  So when the shell sees cd.., it treats it as a four-letter word, no different from cdef or cd56, and so it looks for a command called cd...1  It doesn’t break it into two words just because d is a letter and . isn’t (the way CMD does; see below).
______________
1 As pointed out by Bodo, you can define an alias (or a shell function (or a shell script)) called cd...  Of course it’s probably a bad idea to write a shell script called cd.. (or cdanything), because a shell script can’t cause the shell that calls it to change directory.

Why does cd.. work in CMD?

The rules for how CMD parses commands seem to be complex and not well documented.

  • Wikibooks says:

    The parsing of a command line into a sequence of commands is complex, and varies subtly from command interpreter to command interpreter.

  • David Deley says that, in Windows, “Everyone Parses Differently”:

    You'll get different results if you pass a command line to ShowParams.exe (written in C/C++), ShowParams.vbs (VBScript), or ShowParams.bat (batch file)…

  • How does the Windows Command Interpreter (CMD.EXE) parse scripts? (on Stack Overflow) contains extensive, detailed answers to the titular question.

… but (in about an hour’s worth of searching) I couldn’t find anything that specifically addresses this issue of how CMD determines what the command is (i.e., what we would call argv[0] in a C program in Unix).

I’ve done some testing / experimentation (on Windows 7).  One pattern I’ve observed is that, after a first tokenization pass (breaking the command line at spaces and high-precedence characters like <, >, &, |, , and /), CMD looks at the first word on the command line, and breaks it apart at certain other non-alphanumeric characters (including ., +, =, and \).

  • If the word up to the first such non-alphanumeric character is a builtin command that doesn’t take arguments, then that command is executed.  For example, cls., cls.., cls.abc, cls.a.b.c, cls.exe, cls=, cls=abc, cls+, cls+abc, cls\, cls\abc, and many more variations, act like just plain cls and clear the screen.  Ditto for pause.

    These seem, at first, to be exceptions to the above:

    • cls/ and cls/a/b/c give an error message.
    • cls/? gives a help message.
    • pause/ and pause/a/b/c simply pause (i.e., they act like just plain pause).
    • pause/? gives a help message, says “Press any key to continue . . .”, but doesn’t wait for you to press a key.  (This is a bug.)
       

    But the above are consistent with the idea that CMD breaks things into tokens at / characters.  cls/ behaves the same as cls /, for example.

  • echo is special case:
    • echo on turns the echo on.
    • echo off turns the echo off.
    • Just plain echo reports the state of the echo flag.
    • But, if echo is immediately followed by a non-alphanumeric character (like ,, . or /), then that character is ignored, but special processing for the rest of the command gets disabled.  So, if you want to print the word “on” or “off”, use echo.on or echo.off, and, to print a blank line, use echo..  And so echo.. acts like echo . [sic].
  • TL;DR
    In other cases, CMD seems to look up to the last dot (or group of dots), and if that substring is a builtin command, it interprets it as that builtin command.  So cd.., dir.., type..\filename.txt and copy..\filename newname all act like there was a space before the first dot. 

But this works only for builtins; for example, calc.. and find.. get the “… is not recognized as an internal or external command, operable program or batch file.” error.  So, for some fun examples:

  • If you have a program called abcd.efg.exe, you can run it by typing abcd.efg.  But if it’s called cd.efg.exe, then cd.efg fails, because it’s parsed as cd .efg.  You would have to type cd.efg.exe.
  • Similarly, if you have a subdirectory called abcd in the current directory, and a program called efg.exe in that subdirectory, you can run it by typing abcd\efg.  But if the subdirectory is called cd, then cd\efg fails, because it’s parsed as cd \efg.  You would have to type cd\efg.exe.
  • 1
    In general, the attempt to interpret .,.. and `` is rooted in the intent to process windows paths (which might include spaces and could be relative (../path)). – Isaac Jul 17 at 22:24
3

On Linux terminals we have to separate the dots from the cd command. I'd like to know how/why is this necessary for the parser to work.

Probably the regExp or whatever is parsing the commands is not including the dot as a possible character immediately after the command.

Yes, in a sense. Shells (well, at least POSIX ones) treat . as a regular character, just like letters and digits. Some other characters have special meanings (when unquoted), like ;, <, ( etc. Whitespace and some special characters can be used to split the command into words.

Considering that directories and filenames can contain dots (and especially the fact that .. is a common directory name), it's a good idea for the command line parser to treat the dot as a regular character. Otherwise, how would a command like ../foo.sh some args work? Would the first part get split between the o and the dot? Or already between the dot and the slash?

Allowing a command like cd.. to be treated like cd .. would likely require a bunch of special cases, which would make the implementation awkward and confuse users. It's far simpler to just split at the whitespace, and then take the first word as the command (regardless of if it's a builtin, a function, or an external command). It's not strictly necessary, it just seems simpler than the alternative.

  • No, not only whitespace works to split command line into words. Any redirection or control operator (in Posix) or any metacharacter (in ksh, bash, etc) works to delimit a word. – Isaac Jul 17 at 21:58
  • @Isaac, yeah, you're right. I ignored special characters since most of them will just terminate the command, too (so you don't get any useful words after that). ; ends the command, ( causes a syntax error, and I stopped thinking there. Redirections would indeed work, echo<foo bar results in the two "arguments" echo and bar (I can't remember what the first word that ends up as the command name is called.) I edited that, even though it muddies the idea a bit. – ilkkachu Jul 18 at 5:58
1

On Linux terminals the dots from the cd command have to be separated

Short answer: Because POSIX requests it. The POSIX parser is a very-very basic one.

The word delimiters in posix are either space, tab, redirection operators (< > >| << >> <& >& <<- <>) or control operators (& && ( ) ; ;; <newline> | || ).

That's it.

A cd.. is considered a single word and is searched as one command (usually) in /bin.

Other shells (ksh,bash) call the "word delimiters" (word delimiters): metacharacters, and list them as:

;   &   (   )   |   <   >   new-line   space   tab
0

cd in Windows is an internal command and you cannot find it as an executable in windows.

Here is a list of internal DOS commands.

Whereas cd in a Linux system is an actual program which you can find in /bin.

[root@localhost j]# ls /bin/cd
/bin/cd

And it can only take arguments with space, because when you do cd or anycommand followed by few args, the bash looks for the first thing you typed in the $PATH env variable which is probably set to /usr/bin, executes the program and feeds anything you typed later as args. When you type cd.. the bash will look exactly for cd.. under /usr/bin and gives you an error as it cannot find such program.

This is a simply better design.

  • 4
    There is an external command for cd, but that's not what you're executing when you run cd – muru Jul 8 at 15:16
  • 1
    Not all Linuxes have /bin/cd//usr/bin/cd, e.g. none of my Debian's do. Even if it does exist, and you run it, it won't do what you want. – ilkkachu Jul 8 at 16:37
  • @ilkkachu, what do you mean by "it won't do what you want"? – Vignesh SP Jul 8 at 22:23
  • 2
    Since an external command like /bin/cd is run in a separate process, and the current dir is a per-process attribute, running the external cd won't change the current dir in the calling shell. The external cd can only be used to check if a directory could be chdir into. – mosvy Jul 8 at 23:11
  • 1
    You’re comparing apples and oranges. In Windows, mkdir..\newdirectory does work. – G-Man Jul 17 at 19:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.