cd ~<user> is possible but why can't we cd ~"$USER" or cd ~${USER}
That very much depends on the shell and the order the expansions are done in those shells.
~$user
expands to the home directory of the user whose name is stored in $user
in csh (where that ~user
feature comes from), AT&T ksh, zsh, fish.
Note however these variations:
$ u=daemon/xxx csh -c 'echo ~$u'
/usr/sbin/xxx # same in zsh/fish
$ u=daemon/xxx ksh93 -c 'echo ~$u'
~daemon/xxx
$ u=daemon/xxx csh -c 'echo ~"$u"'
Unknown user: daemon/xxx.
$ u=daemon/xxx zsh -c 'echo ~"$u"'
/usr/sbin/x # same in fish
$ u=" daemon" csh -c 'echo ~$u'
/home/stephane daemon
$ u=" daemon" zsh -c 'echo ~$u'
~ daemon # same in ksh/fish
$ u="/daemon" csh -c 'echo ~$u'
/home/stephane/daemon # same in zsh
$ u="/daemon" fish -c 'echo ~$u'
~/daemon # same in ksh
It expands to the home directory of the user named literally $user
in bash
(provided that user exists, which is very unlikely of course).
And to neither in pdksh
, dash
, yash
, presumably because they don't consider $user
to be a valid user name.
Tilde expansion is a separate step in the processing of the command line. It happens just before variable expansion.
If the tilde is followed by something other than a slash, it will expand to the home directory of the user whose name is following the tilde, as in, for example, ~otheruser
. Since $USER
is not expanded at that point and since it's unlikely to correspond to a valid username, the tilde is left unexpanded.
$USER
is likely to be the username of the current user, so your expression could probably be replaced by just ~
.
As other answers have pointed out the behavior depends on which order the shell does ~
and $
expansions and whether it will even do both for the same word.
The behavior you were looking for is possible to achieve in bash
by a very small change to your command. Simply prefix the command with eval
.
eval "cd ~$USER"
will change to the home directory of the user given by the username in the variable USER
, provided $USER
doesn't contain characters special to the shell (if there's a remote chance that it might, you should not pass it as argument to eval
as that would be dangerous) or /
characters and that there's an entry for that user in the system's user database.