33

I was confused, trying to copy some files from one PC to another. I have it figured out, but the syntax is still confusing to me. This works:

scp ~/Desktop/Volenteer.png jay@server.ip:~j0h/b

which puts Volenteer.png in the folder /home/j0h/b. However, this doesn't work:

scp ~Desktop/Volenteer.png     jay@server.ip:~j0h/b

This also fails, giving an exit status 1 file not found:

scp ~/Desktop/Volenteer.png     jay@server.ip:~/j0h/b

As does this:

scp ~Desktop/Volenteer.png     jay@server.ip:~j0h/b

So clearly, there is some difference between ~ and ~/ That difference is the presence of /

$~/
bash: /home/j0h/: Is a directory
$ ~
bash: /home/j0h: Is a directory

So why in scp, does the ~ resolve to ~/ ? That is a guess, I cant verify that's what is happening. But it seems inconsistent, and therefore confusing. Is this a bug in scp? or is there something about tilde I am missing?

Jorge Castro
  • 73,717
j0h
  • 15,365

4 Answers4

73

~ 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     jay@server.ip:~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     jay@server.ip:~/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 
  ~+   ~-
muru
  • 207,228
22

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.

Oli
  • 299,380
4

The symbol ~ is used as a shortcut for /home/user in bash, so in the case of ~/Desktop/Volenteer.png it is shorthand for /home/user/Desktop/Volenteer.png.

So as you can see the /, as always, shows an new level in the file system hierarchy.

Mark Kirby
  • 18,949
  • 19
  • 79
  • 116
3

~ is shorthand for the environment variable $HOME on most c shell derivative/supporting POSIX compliant shells. the most common use for ~ is when referencing your own home directory or that of another user's home:

cd ~ # ie shell, take me to my home folder

cd ~root # i.e. shell, take me to root's home folder

To find the home directory for any local user on a POSIX system (UNIX, Linux, OS X, BSD) that is using the passwd(5) database run awk on /etc/passwd like so:

awk -F: '{ print $1,$(NF-1) }' /etc/passwd

This will list each local user and their home directory.

muru
  • 207,228