41

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
9
  • 29
    Ask yourself this: if if didn't work that way, how would you cd into a directory named ~? May 5, 2018 at 15:11
  • 2
    As a sidenote, if you're writing a script you should rather use absolute paths and avoid cd alltogether. Use variables to store pathnames you don't want to type multiple times, e.g. pf=~/.wine/drive_c/Program\ Files/; cp /path/to/file "$pf"
    – dessert
    May 5, 2018 at 15:40
  • 2
    @Jörg W Mittag: Why would a sensible system allow you to name a directory '~'? How about a directory named '/'? (Of course I realize that just having a directory called "Windows Program Files" means we're probably not dealing with a sensible system :-()
    – jamesqf
    May 5, 2018 at 17:37
  • 8
    @jamesqf: Why would a sensible system presume to know better than me what I want to name my files and directories? Also, I never understood why Unix went with magic in-band signaling of path component separators and path terminators. What's wrong with a file/directory named / or NUL? May 5, 2018 at 17:40
  • 4
    @JörgWMittag presumably cd ./~
    – k_g
    May 6, 2018 at 3:31

4 Answers 4

86

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"
    
5
  • 4
    @rexkogitans ~'/...' won't work and isn't what this answer has. ~/'...' or ~/"..." will work.
    – hvd
    May 5, 2018 at 13:33
  • tld;dr: because thats shell syntax May 5, 2018 at 14:48
  • @hvd thanks. Fixed typo. This is the most complete answer and also explains how to solve what the OP wants to do. ~/'path' is the way to go. May 5, 2018 at 14:49
  • 2
    @hvd just little of curiosity, why wouldn't ~'/...' work? The slash isn't a special character so it seems it should work either inside or outside the quotes. May 5, 2018 at 18:41
  • 7
    @KodosJohnson Have a look at the Bash manpage's section about "Tilde Expansion". The relevant paragraph of that is also quoted in dessert's answer below. TL;DR: Tilde expansion takes place if the first character in a word is an unquoted tilde, then everything between that tilde and the next unquoted slash is considered the "tilde prefix". If this prefix is not a valid thing like +, -, a number, or a user name (quotes in there are not allowed either), the expansion fails and you get a literal ~ character.
    – Byte Commander
    May 5, 2018 at 18:52
18

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

1
  • ~ is not an alias in the sense bash interprets it: Aliases allow a string to be substituted for a word when it is used as the first word of a simple command.. As I explain in my answer below, it's rather an expansion.
    – dessert
    May 5, 2018 at 11:38
16

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”
0
3

Explore using echo command

The easiest way of exploring how things work in bash is with the echo command. In the case of ~ use this:

$ echo ~
/home/rick
$ echo '~'
~
$ echo "~"
~
$ echo `~`
bash: /home/rick: Is a directory

As you can see, when you single quote or use double quotes around ~ it is interpreted literally as a string and not expanded as a variable. When you use backticks (`) it is executed as a command and generates an error message.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .