31

$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?

45

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.
  • 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 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 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 at 5: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 at 5:06
  • 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 git.savannah.gnu.org/cgit/bash.git/tree/lib/readline/… – Mirek Długosz Sep 30 at 11:53
17

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
13

~ 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.

3

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.

  • 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 3 at 9: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 5 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 5 at 21:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.