20

cd ~

does the same thing as

cd $HOME

which is also the same as

cd /home/tandu

However,

cd ~not-tandu

changes to /home/not-tandu

Is this purely a syntactic choice? How is this handled by the kernel (or the cd execuable?) Is there a special case for ~ to add the slash if everything else is omitted? That is to say, ~/ and ~ change to the same directory, but ~a is one directory up. The same cannot be said for any other directory you change to.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
  • 3
    Feel free to compare ~not-tandu and ~/not-tandu, one points to the user not-tandu home dir and the other points to the dir not-tandu in your homedir. – Johan Mar 17 '12 at 07:50
  • 5
    It's not the kernel or the "cd executable" (since there is no such thing) - it's a shell built-in. – Paul Tomblin Mar 17 '12 at 11:47
  • Since you not mention it: cd without any parameters works like cd ~. If you replace cd with echo you can see to what the expression is expanded by the shell. – jofel Mar 17 '12 at 23:43

3 Answers3

25

~ is an alias for $HOME provided by a number of shells, but $HOME is more universal. $HOME actually asks the shell to insert (substitute) the environmental variable HOME here. There are quite a number of different environmental variable that can be substituted, try running env for a list. Note that ~ is not always recognized when it's not at the beginning of a word. Try these two commands for comparison:

ls /~
ls /$HOME

The first gets passed to the ls executable as /~ which then tries to look at a file called ~ in the root directory, the second expands $HOME and becomes //home/user which is then passed to the ls executable as a command-line argument. All POSIX systems (POSIX is the standard for how UNIX and Linux systems operate) allow multiple slashes to be treated the same as one slash so //home/user is the same as saying /home/user. ~username is a shortcut for telling the shell to look up username in the passwd file and return their home directory. There is no equivalent environment variable. All of these substitution are done by the shell and are supported by most of them, but only environment variables like $HOME are guaranteed to be supported by all shells. Also, cd is actually a built-in command. It's a special directive that tells the shell itself to change directories. It's not like other shell built-ins that can be implemented as a separate executable like echo is because it's used to change a fundamental attribute of the shell process. echo is merely a shell built-in for performance reasons, but in the good old days of UNIX, was only available as it's own executable /bin/echo.

penguin359
  • 12,077
  • re "which then tries to look at a file called ~ in the root directory"; That's for all unix flavors? – Pacerier May 25 '19 at 13:41
17

~foo means 'the home directory of user foo'.

This isn't done by the kernel, it's interpreted by the shell. Whenever the shell sees ~foo as an argument, it transparently replaces it with the home directory of user foo and passes that in its place. So when you run cd ~tandu, the shell is actually running cd /home/tandu.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
phemmer
  • 71,831
  • 1
    What specifically does this replacement and with what algorithm? Is it cd or the shell? What if you are not running a shell? Is it a simple "if ~ is followed by something, expand differently?" or is there some other special handling for this unique condition? – Explosion Pills Mar 17 '12 at 05:29
  • 9
    See the Bash manual on Tilde Expansion. (Many other shells and programs follow similar rules.) – cjm Mar 17 '12 at 06:17
  • 4
    @tandu: the shell does cd, there is not external executable to do it (it wouldn't be possible) – Mat Mar 17 '12 at 06:40
  • 1
    @tandu: if you're not running a shell (e.g. trying this out using exec(2)), shell expansion doesn't take place. Without shell expansion, ~ doesn't get replaced by anything — it's just another perfectly valid character. This bit me in my early SunOS days because /bin/sh didn't grok ~. – Alexios Mar 17 '12 at 13:16
6

~ followed by a username expands to that user's home directory.