Why can't I cd to a quoted tilde ('~')?

Writing my first script so I'm sure this is a basic question, but can someone please explain to me why I can:

cd ~
cd bin
cd ~/bin
cd 'bin'

But not

cd '~'
cd '~/bin'

I need to cd to a directory path with a space in one of the directory names, so I need the quotes (it's Windows Program Files under wine). I can get around it with two cd commands, but why can't I put ~ in quotes?

If I type cd '~' (or cd "~") I get:

bash: cd: ~: No such file or directory

As @karel noted in his answer, ~ is a special character and expanded by Bash into the current user's home directory. See Bash's manual on "Tilde Expansion", or search for the headline "Tilde Expansion" in the man page (man bash).

Any kind of quotation around the ~ prevents this tilde expansion.


To answer your question about how you still can use it to cd into a directory with spaces in its name, there are a few alternatives:

  • Omit quotes and escape the spaces with backslashes instead:

    cd ~/foo/spaces\ are\ cool/bar
    
  • Quote the rest of the path, but omit them around the tilde and the first slash:

    cd ~/"foo/spaces are cool/bar"
    

    As you see, you can concatenate quoted and unquoted strings in Bash by simply writing them next to each other without any spaces in between.

  • Use the environment variable $HOME instead of the tilde, which still gets expanded inside "double quotes" (but not 'single quotes'):

    cd "$HOME/foo/spaces are cool/bar"
    

~ is a special character that is interpreted by the shell as the logged in user's home directory. '~' is interpreted by the shell as a literal ~ character, not as the logged in user's home directory because enclosing a string inside two single quote characters results in that string being interpreted as a literal text string.


This is a bash feature called Tilde Expansion. Citing man bash:

If a word begins with an unquoted tilde character (`~'), all of the characters preceding the first unquoted slash (or all characters, if there is no unquoted slash) are considered a tilde-prefix. If none of the characters in the tilde-prefix are quoted, the characters in the tilde-prefix following the tilde are treated as a possible login name. If this login name is the null string, the tilde is replaced with the value of the shell parameter HOME. If HOME is unset, the home directory of the user executing the shell is substituted instead.

For the expansion to work the tilde character ~ needs to be unquoted, else the character is taken literally and cd fails if there is no directory named ~ present in the current directory. See this entensive answer for an explanation of quoting in bash. If you need to quote part of the path, you can therefore:

  1. quote at least the characters that need quoting with single quotes, e.g.

    ~/dir' 'with' 'spaces/
    

    or

    ~/'dir with spaces/'
    
  2. quote at least the characters that need quoting with double quotes, e.g.

    ~/dir" "with" "spaces/
    

    or

    ~/"dir with spaces/"
    
  3. quote only the characters that need quoting with backslashes , e.g.

    ~/dir\ with\ spaces/
    

Tilde Expansion has some more interesting features, e.g.:

  • ~+ expands to the value of PWD, i.e. the current working directory
  • ~- expands to the value of OLDPWD, i.e. the previous working directory
  • ~john expands to the home directory associated with the login name “john”