Does ~ always equal $HOME
What's important to understand is that ~
expansion is a feature of the shell (of some shells), it's not a magic character than means your home directory wherever it's used.
It is expanded (by the shell, which is an application used to interpret command lines), like $var
is expanded to its value under some conditions when used in a shell command line before the command is executed.
That feature first appeared in the C-shell in the late 1970s (the Bourne shell didn't have it, nor did its predecessor the Thompson shell), was later added to the Korn shell (a newer shell built upon the Bourne shell in the 80s). It was eventually standardized by POSIX and is now available in most shells including non-POSIX ones like fish
.
Because it's in such widespread use in shells, some non-shell applications also recognise it as meaning the home directory. That's the case of many applications in their configuration files or their own command line (mutt
, slrn
, vim
...).
bash
specifically (which is the shell of the GNU project and widely used in many Linux-based operating systems), when invoked as sh
, mostly follows the POSIX rules about ~
expansion, and in areas not specified by POSIX, behaves mostly like the Korn shell (of which it is a part clone).
While $var
is expanded in most places (except inside single quotes), ~
expansion, being an afterthought is only expanded in a few specific conditions.
It is expanded when on its own argument in list contexts, in contexts where a string is expected.
Here are a few examples of where it's expanded in bash
:
cmd arg ~ other arg
var=~
var=x:~:x
(required by POSIX, used for variables likePATH
,MANPATH
...)for i in ~
[[ ~ = text ]]
[[ text = ~ ]]
(the expansion of~
being taken as a pattern in AT&Tksh
but notbash
since 4.0).case ~ in ~) ...
${var#~}
(though not in some other shells)cmd foo=~
(though not when invoked assh
, and only when what's on the left of the=
is shaped like an unquotedbash
variable name)cmd ~/x
(required by POSIX obviously)cmd ~:x
(but notx:~:x
orx-~-x
)a[~]=foo; echo "${a[~]} $((a[~]))"
(not in some other shells)
Here are a few examples where it's not expanded:
echo "~" '~'
echo ~@ ~~
(also note that~u
is meant to expand to the home directory of useru
).echo @~
(( HOME == ~ ))
,$(( var + ~ ))
- with
extglob
:case $var in @(~|other))...
(thoughcase $var in ~|other)
is OK). ./configure --prefix=~
(as--prefix
is not a valid variable name)cmd "foo"=~
(inbash
, because of the quotes).- when invoked as
sh
:export "foo"=~
,env JAVA_HOME=~ cmd
...
As to what it expands to: ~
alone expands to the content of the HOME
variable, or when it is not set, to the home directory of the current user in the account database (as an extension since POSIX leaves that behaviour undefined).
It should be noted that in ksh88 and bash
versions prior to 4.0, tilde expansion underwent globbing (filename generation) in list contexts:
$ bash -c 'echo "$HOME"'
/home/***stephane***
$ bash -c 'echo ~'
/home/***stephane*** /home/stephane
$ bash -c 'echo "~"'
~
That should not be a problem in usual cases.
Note that because it's expanded, the same warning applies as other forms of expansions.
cd ~
Doesn't work if $HOME
starts with -
or contains ..
components. So, even though it's very unlikely to ever make any difference, strictly speaking, one should write:
cd -P -- ~
Or even:
case ~ in
(/*) cd -P ~;;
(*) d=~; cd -P "./$d";;
esac
(to cover for values of $HOME
like -
, +2
...) or simply:
cd
(as cd
takes you to your home directory without any argument)
Other shells have more advanced ~
expansions. For instance, in zsh
, we have:
~4
,~-
,~-2
(with completion) used to expand the directories in your directory stack (the places you'vecd
to before).- dynamic named directories. You can define your own mechanism to decide how
~something
is being expanded.
In any version of Bash on any system, yes. ~
as a term on its own is defined to expand to:
The value of $HOME
so it will always be the same as whatever $HOME
is to the current shell. There are several other tilde expansions, such as ~user
for user
's home directory, but a single unquoted ~
on its own will always expand to "$HOME"
.
Note that the behaviour of ~
and $HOME
can be different in some cases: in particular, if $HOME
contains spaces (or other IFS characters), then $HOME
(unquoted) will expand to multiple words, while ~
is always a single word. ~
expands equivalently to "$HOME"
(quoted).
In regard to your specific question:
[[ $HOME == ~ ]]
is always true, because [[
suppresses word-splitting. [[ ~ == $HOME ]
may not be if HOME
has pattern matching characters in it, but [[ ~ == "$HOME" ]]
(i.e., quoted "$HOME"
) is always true. Using it inside single brackets can be a syntax error for values of HOME
containing spaces or special characters. For any sensible home directory configuration ~
and "$HOME"
are the same and compare as equal.
Stéphane Chazelas has noted a case in the comments where ~
and $HOME
give different values: if you unset HOME
, then when you use ~
Bash will call getpwuid
to read a value out of the password database. This case is excluded by your condition of having no configuration changing $HOME
, but I'll mention it here for completeness.