38

$HOME and ~ usually refer to the same thing. That is, they are the path to the "user's home" directory which is of the general form "/home/userName".

When, if ever, do these not refer to the same directory?

H2ONaCl
  • 9,693

5 Answers5

49

Both $HOME and ~ point to the same folder, the current user's home folder, but both are very different things.

  • $HOME is an environment variable, that is set to contain the home folder of the current user.
  • ~ is a shell expansion symbol, i.e., one of the symbols that is processed before the actual command is performed. ~ alone expands to the value of $HOME. ~nemo expands to the home directory of user nemo. A shell expansion symbol is a character (or pair of characters) that is processed/interpreted by the shell to build the actual command. Another example of a shell expansion symbol is *, which is used to expand file names.
vanadium
  • 88,010
  • 1
    ~ expands to $HOME, or %APPDATA% on Windows. If they are not defined, it will look for path in "the password database" (which usually means /etc/passwd, but might be LDAP or some other data source). Some 20 years ago you could have been warned that $HOME might not be set on some machines, while ~ was guaranteed to expand to something. – Mirek Długosz Sep 29 '19 at 22:36
  • This difference is notable in programs like make, when you need to know which of the two you need – D. Ben Knoble Sep 29 '19 at 23:13
  • 3
    @MirekDługosz At least on git bash on Windows, ~ expands to $HOME (equal to $HOMEPATH), not $APPDATA. And on cmd.exe, ~ does not expand. – hyde Sep 30 '19 at 05:04
  • 1
    @vanadium HOME is an environment variable (an OS concept, in sh shells for example set with export or declare -x), not a shell variable (definition of which depends entirely on shell, but in sh shells it is usually set with foo=value or with set or in a few other ways). – hyde Sep 30 '19 at 05:06
  • @hyde, thanks for your correction. You are right indeed: I corrected the term. – vanadium Sep 30 '19 at 09:43
  • 1
    @hyde I phrased that wrong. bash will check for $HOME, if it is not set it will check for %APPDATA%, but only on Windows; if it is not set, it will look up "the password database". See http://git.savannah.gnu.org/cgit/bash.git/tree/lib/readline/tilde.c#n351 – Mirek Długosz Sep 30 '19 at 11:53
  • Strictly speaking, HOME is a shell variable initialized from the environment and marked for export to the environment to any child processes. – chepner Sep 30 '19 at 20:22
  • @Mirek That's interesting... and counter-intuitive too. I can see why they did it, though. – gronostaj Oct 01 '19 at 06:36
19

One way they differ is in how the Bash shell converts them when enclosed in the " kind of quotation marks.

If you use echo like this, without any quotes, then ~ and $HOME have the same effect:

$ echo ~
/home/elias
$ echo $HOME
/home/elias

However, with " quotation marks around them, the result differs:

$ echo "~"
~
$ echo "$HOME"
/home/elias
Elias
  • 2,039
14

~ only expands as a part of a tilde-prefix which by definition must start at the beginning of the word. Additionally, as it was once part of globbing patterns, ~ will not work inside double quotes. So, "~" or a~b will result in a literal value of ~ being preserved.

A single ~ (or a ~ followed by a /) will expand to current user's home:

$ echo ~/.ssh
/home/user/.ssh

A ~ followed by a username will expand to home folder of that user:

$ echo ~root/.ssh
/root/.ssh

A ~ followed by a + or a - and an optional number will expand to elements of the directory stack:

$ cd /etc
$ echo ~+0
/etc

$HOME is the equivalent of a single ~, which instead follows syntax rules for variables. For instance, it expands inside double quotes, can be unset, and string manipulation operands can be applied to it.

4

This depends a lot on what does the expansion. In bash, ~ is a convenient way to get the home directory without triggering filename expansion or word splitting even though its unquoted. For example:

$ HOME='/*'
$ echo $HOME
/bin /boot /dev /etc /home /lib /lib64 /media /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var
$ echo ~
/*

Or:

$ HOME='/ a b'
$ printf "|%s|\n" $HOME ~
|/|
|a|
|b|
|/ a b|

So if you're wrestling with quotes for some reason (in which case you should really re-think the whole thing, it's easier to wrestle pigs), ~ might be more convenient.


Elsewhere, in Python, for example, ~ and $HOME have to be expanded by different functions. Some other places allow variables and don't allow other shell syntax like wildcards or tilde expansion (e.g., ~/.pam_environment, which has a special syntax for variable expansion). Yet other places allow tilde expansion as an exception (e.g., systemd), but query the passwd database directly instead of using $HOME.

homeboy
  • 41
  • 1
  • Another big difference, which you show here, but don't mention, is that you can change the value of $HOME, but you can't (directly) change the value of ~. – Joe Oct 03 '19 at 09:34
  • So I asked when do $HOME and ~ not refer to the same thing -- they normally do by default -- and then you deliberately assign to the environment variable to make them not refer to the same thing. This is a good demonstration but needlessly confusing. – H2ONaCl Oct 05 '19 at 21:50
1

$HOME/ is more likely to work in standard POSIX.2 Bourne /bin/sh as tilde expansion is an extension found in BSD csh tcsh GNU bash and others.

If you want to write scripts portable to busybox or dash or BSD sh, invest in the extra letters lest you crash with ~/: No such file or directory on certain systems.

I also find $HOME/ more readable.

  • In a script readability and visibility are important. Perhaps this is why my scripts use $HOME and seldom use ~. My former self probably knew this. – H2ONaCl Oct 05 '19 at 21:58