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?
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?
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 cd
s. 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.
~
is to do cd ~user/download
to go to an user's download directory.
– ott--
Oct 01 '15 at 19:47
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
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.
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
~ 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.
root
's home directory is usually outside /home
– Dmitry Grigoryev
Sep 30 '19 at 07:23
cd ~
vscd $HOME
vscd ~not-tandu
. This question is asking aboutcd
vscd ~
. – Jul 27 '13 at 12:28