Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I know this has probably been asked before, but I couldn't find it with Google.

Given

  • Linux Kernel
  • No configurations that change $HOME
  • bash

Will ~ == $HOME be true?

share|improve this question
2  
I believe so, but this is not a Linux-specific issue. Rather, I believe ~ will be equivalent to $HOME in any POSIX environment; but I could be wrong. –  HalosGhost Jul 26 at 3:11
2  
Despite the answers below… not always. Compare echo "~" and echo "$HOME". –  Sparhawk Jul 26 at 3:46
    
@Sparhawk Wait, so 1+1 isn't 2? It's a conspiracy! The government is hiding something from us! :P –  Doorknob Jul 26 at 6:13
1  
@Sparhawk, you'll notice the OP actually did not quote either the ~ or $HOME. :P –  HalosGhost Jul 26 at 7:51
2  
@HalosGhost Ah, good point. (Also, I later noticed that Michael Homer's answer mentions "a single unquoted ~".) Anyway, something to keep in mind for the casual reader, like myself. –  Sparhawk Jul 26 at 7:55

2 Answers 2

up vote 23 down vote accepted

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 Thomson 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), though see the bug mentioned below.

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 like PATH, MANPATH...)
  • for i in ~
  • [[ ~ = var ]]
  • case ~ in ~) ...
  • ${var#~} (though not in some other shells)
  • cmd foo=~ (though not when invoked as sh)
  • cmd ~/x (required by POSIX obviously)
  • cmd ~:x (but not x:~:x or x-~-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 user u).
  • echo @~
  • (( HOME == ~ )), $(( var + ~ ))
  • with extglob: case $var in @(~|other))... (though case $var in ~|other) is OK).
  • when invoked as sh: ./configure --prefix=~, 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 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've cd to before).
  • dynamic named directories. You can define your own mechanism to decide how ~something is being expanded.
share|improve this answer

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.

share|improve this answer
    
However, /bin/sh might not be bash. I'm not sure that Posix sh specification tells about ~ –  Basile Starynkevitch Jul 26 at 5:38
    
POSIX specifies ~. ~ was not in the Thomson or Bourne shell (that in their time were available as /bin/sh). It's not in rc or its derivatives (where it's used for something else) –  Stéphane Chazelas Jul 26 at 6:47
    
You also need to quote $HOME in [[ xx = $HOME ]] in ksh and bash as otherwise it's considered as a pattern (so the above would return false for a value of HOME like /[a]) –  Stéphane Chazelas Jul 26 at 6:50
3  
In a few shells including bash, if HOME is unset, ~ expands to the home directory of the user from the passwd database. So that's a case where ~ may not expand to the value of $HOME. –  Stéphane Chazelas Jul 26 at 6:55
1  
Note that bash before bash4 used to perform globbing upon tilde expansion (try HOME='/*' bash -c 'echo /*'). So HOME=/*; [ "$HOME" = ~ ] would return an error there. –  Stéphane Chazelas Jul 26 at 7:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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