21

I am wondering, if cd alone sends me to my home folder and cd ~ does the same, why was the ~ added in the first place then?

Is it something specific to BASH or would they behave differently in another Shell?

Luis Alvarado
  • 830
  • 1
  • 9
  • 20
  • 3
    Definitely not a duplicate. That question is asking about cd ~ vs cd $HOME vs cd ~not-tandu. This question is asking about cd vs cd ~. –  Jul 27 '13 at 12:28

4 Answers4

22

The ~ can be used for more than just that. Any command can profit from having a shortcut to the home folder. So it is not necessary if you want to cd into your home, but what about ~/.config?

$ cd ~/.config

Otherwise you'd have to write out the home path, use the $HOME var, or do two cds. Also for copying or moving files:

$ cp ~/downloads/some-file some/path/

Since most of your files are in the home it's always good to have a shortcut.

dhag
  • 15,736
  • 4
  • 55
  • 65
ahilsend
  • 1,464
  • Hi ahilsend, actually my question is more oriented towards why the 2 ways. I already know about ~ using the $HOME variable but, with this is mind, why does "CD" alone also send me to home. Why 2 ways for the same purpose? – Luis Alvarado Jul 27 '13 at 10:13
  • 4
    @CYREX My guess would be to save typing for the very common case of wanting to move to your home directory. – user Jul 27 '13 at 11:19
  • 1
    The other use of the ~ is to do cd ~user/download to go to an user's download directory. – ott-- Oct 01 '15 at 19:47
  • 1
    @LuisAlvarado: I know it's years late, but since I don't see anyone else mentioning it: to answer your question about why there are two apparently redundant ways to specify the home directory, the real answer is that cd doesn't know about ~. Tilde expansion is something the shell does before executing the cd command. So cd uses a default of $HOME if no argument is supplied, otherwise it changes to the directory specified by the argument - and it sees the actual directory path, not the ~ character. – Michael Burr Feb 24 '21 at 09:06
7

Doing cd is basically calling cd with no arguments and in accordance with cd behavior "...if dir is not supplied, the value of the HOME shell variable is the default." (from bash manual). By contrast, cd ~ is when you supply argument to cd command, which happens to be ~ and shell will perform tilde expansion. As far as going back to user's home directory - there's no difference. In either case, HOME environment variable will be queried:

$ env 'HOME=/usr' bash -c 'cd;pwd; cd ~;pwd'                                      
/usr
/usr

Effectively, this also has no difference from cd $HOME. However, whereas cd will do one and only thing, tilde can be used to perform other expansions such as ~+ for current working directory.

However, interestingly enough we can unset HOME to break cd but ~ will still work:

$ bash -c 'cd /usr;unset HOME;cd;pwd;cd ~;pwd'                                    
bash: line 0: cd: HOME not set
/usr
/home/xieerqi

Why ? Again, answer in the manual:

If HOME is unset, the home directory of the user executing the shell is substituted instead. Otherwise, the tilde-prefix is replaced with the home directory associated with the specified login name.

Notice that unsetting is different that making empty variable HOME= and does have effect. Documentation specifically talks about unsetting variable. Making variable equal to empty string has effect opposite to what we'd expect:

bash-4.3$ env 'HOME=' bash -c 'cd /usr;set|grep "^HOME"; stat -c "%F" ~;cd;pwd'
HOME=
stat: cannot stat '': No such file or directory
/usr

Here you can see that making HOME empty string breaks both tilde and cd behavior.


Tilde and $HOME have somewhat of a difference and different reason for existence. $HOME is a shell variable, which also co-incidentally happens to be one of the environment variables - and that is available to all programs; in C you would use environ() to access that. By contrast, tilde is shell-specific syntax which performs tilde expansion, although you can use wordexp() function to perform shell-like expansion(reference) in C as well.

The reason why ~ represents HOME has been answered in this question: once upon a time the tilde character shared same key with HOME on Lear-Siegler ADM-3A terminal. HOME by contrast is environment variable that had purely symbolical meaning and no physical representations.

In addition, the fact that HOME is an environment variable allows us to unset it, where as we can't set ~ to something else via simple means.

# cd ~ will still work, because ~ is blank, so it's same as just cd
$ bash -c 'unset HOME; echo $HOME; cd ~;pwd'                           

/home/xieerqi
$ env 'HOME=' bash -c 'echo $HOME; cd ~;pwd'                                

/home/xieerqi

Notice the blank line where first echo outputs the unset variable, and the fact that . By contrast, we can't do stuff like this to tilde:

$ bash -c '~=; cd ~;pwd'                                                    
bash: ~=: command not found
/home/xieerqi
$ bash -c '~=$'\0'; cd ~;pwd'                                               
bash: ~=bash: command not found
/home/xieerqi
$ bash -c 'unset ~; cd ~;pwd'                                               
bash: line 0: unset: `/home/xieerqi': not a valid identifier
/home/xieerqi

However, altering HOME does affect ~:

$ env 'HOME=' bash -c 'echo $HOME; stat ~;'                                 

stat: cannot stat '': No such file or directory

In addition, because ~ also works as expansion character, we can do stuff like this to show current working directory:

$ bash -c 'cd /etc/;stat -c "%n" ~+'                                        
/etc

Whereas if we want to do that via environment variables , we need PWD, and HOME remains the same, or if you do things like echo $HOME+ - that's merely string/variable concatenation. But again, ~+ takes information out of environment variables:

$ bash -c 'cd /etc/;PWD="/usr";stat -c "%n" ~+'                             
/usr

NOTE: the ~+ and ~- expansions work in ksh, but not in dash.


To answer some of your specific questions:

Is it something specific to BASH or would they behave differently in another Shell?

No, this should be consistent behavior. ksh, dash, and csh - all behave same with cd or cd ~.

why was the ~ added in the first place then ?

I would say convenience and historic reasons as explained in the linked answer about tilde. Eventually, it grew to perform more than just home directory expansion.

0

Regardless whether you are several folder levels above or below $HOME, the commands cd and cd ~ do the same thing and do not differ - it will send you back to your HOME directory.

HOWEVER: When you are 1 or more folder levels above HOME and you want to go DIRECTLY to a sub-directory 1 or more folder levels below $HOME, the tilde (~) comes in handy by saving you keystrokes when used to substitute the text needed to refer to $HOME when typing a cd command. For instance;

/$ cd    # (or cd ~)
~$ pwd
/home/foo
~$ dir
bar bar2 bar3
~$ cd ..
/$ cd ..
/$ pwd
/
/$ cd /bar3
bash: cd: /bar3: no such file or directory
/$ cd ~/bar3    # (instead of "cd /home/foo/bar3")
~/bar3$ pwd
/home/foo/bar3
Chris Davies
  • 116,213
  • 16
  • 160
  • 287
0

~ stands for /home/username location, so you save some time when typing. For example cd /home/username/Downloads is the same as cd ~/Downloads, but less typing. Both commands do the same, change the working directory to that location.

Ionut
  • 1