How does using the tilde work as a shortcut to my home directory?

~ is your home directory.

~foo is the home directory of user foo, if such a user exists, or just a directory named ~foo, if that user doesn't exist.


Hence, in:

scp ~Desktop/Volenteer.png     [email protected]:~j0h/b

~Desktop will expand to home directory of user Desktop, if such a user exists (and it usually does not), or be just ~Desktop (a path which usually does not exist either).


In:

scp ~/Desktop/Volenteer.png     [email protected]:~/j0h/b

~/j0h will expand to a directory named j0h in jay's home directory, which, again, is unlikely to exist.


It's not ~ and ~/ where the difference occurs, but in ~ and ~foo.


Additionally, ~ can also be used for directory history navigation:

  • ~- is the previous working directory (like $OLDPWD)
  • ~+ is the current working directory (like $PWD)

This is not applicable to scp, since you don't get to change directories in the middle of an scp operation.

And if you use pushd and popd to maintain a directory stack, ~N and ~+N would be the N th directory in the directory stack, as seen in the output of dirs. ~-N would be the N th directory from the end (counting from zero, in both cases). For example:

$ for i in etc usr var tmp; do pushd /$i; done
/etc ~/.vim
/usr /etc ~/.vim
/var /usr /etc ~/.vim
/tmp /var /usr /etc ~/.vim

$ dirs
/tmp /var /usr /etc ~/.vim

Then, the directories in the stack can be accessed using:

/tmp /var /usr /etc ~/.vim
  ~0   ~1   ~2   ~3     ~4
 ~+0  ~+1  ~+2  ~+3    ~+4
 ~-4  ~-3  ~-2  ~-1    ~-0 
  ~+   ~-

Have a read through of the GNU documentation for Bash Tilde Expansion (as I should have before my first iteration of this answer).

~/Desktop and ~j0h are doing fundamentally different things, which explains why ~Desktop doesn't work:

  • A plain ~ is substituted for your current $HOME environment variable, set on login. So ~ resolves to /home/oli for me, and ~/Desktop reads as /home/oli/Desktop. This is where you see the tilda being used most.

  • ~username resolves to the home of that user, as set in /etc/passwd. So ~oli resolves to /home/oli, ~j0h might resolve to /home/j0h but not neccessarily, your homedir can be anywhere.

  • ~not-a-username doesn't resolve. Because Desktop is not a user, ~Desktop isn't substituted. It is taken literally as a file or path named ~Desktop (which doesn't exist here).

And needless to say, this is all happening remotely (it'd be useless in scp if it were replaced with local values). This works because Bash won't substitute ~... if it's preceded by anything but whitespace.