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 [email protected]:~j0h/b

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

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

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

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

As does this:

scp ~Desktop/Volenteer.png     [email protected]:~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?

3

4 Answers 4

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     [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 
  ~+   ~-
3
  • So, ~+ is always equivalent to . then, is that right? Seems redundant.
    – Wildcard
    Apr 4, 2016 at 19:32
  • 2
    @Wildcard well, not exactly. ~+ and ~- use the values of $PWD and $OLDPWD, which are absolute paths. . is always a relative path. So, if there's a command which changes the current working directory when executing, it will see the new path for ., where the path expanded by ~- will remain the same. tar -C is an example, though I admit I can't think of a good use for ~+. $PWD would be just as good, except that you don't need to quote ~+/foo/bar if $PWD contains spaces.
    – muru
    Apr 5, 2016 at 1:36
  • 2
    Thanks, that clarifies it. Actually that's a good example use case right there: Some commands refuse to operate on relative paths for security reasons; with such commands you can't use ./filename but can use "$PWD/filename" or more simply ~+/filename. (And some commands will work on relative pathnames but there is a functional difference, such as ln or tar.)
    – Wildcard
    Apr 5, 2016 at 1:40
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.

4
  • What does getent passwd bin say?
    – muru
    Aug 5, 2015 at 14:05
  • 2
    "bin" is a system user on most Linux machines, with a home directory of /bin.
    – elaforma
    Aug 5, 2015 at 14:31
  • 1
    The failure to expand ~dir is consistent with the GNU docs: "...the characters in the tilde-prefix following the tilde are treated as a possible login name... If the login name is invalid, or the tilde expansion fails, the word is left unchanged." Here, dir is not the name of a user on this system, so it is left unchanged.
    – apsillers
    Aug 5, 2015 at 14:56
  • Thanks all. I should probably read the links I post :)
    – Oli
    Aug 6, 2015 at 7:30
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.

5
  • 3
    only half right, its a shorthand for the $HOME environment variable. ~{user}/ could just be any random path as set by the passwd(5) database file. While yes, the filesytem.org standards does place regular users in /home this is not the case with every user (ie root in /root, and services in /var/... or older unixies using /usr instead of /home) Aug 5, 2015 at 19:25
  • DwightSpencer is correct. I maintain several servers where the users are in /usr/{CLIENTNAME}/home/ and are shared over several inhouse and remote systems (all point to that directory) so only 1 system needs to be maintained. And ~ points to that directory ;)
    – Rinzwind
    Aug 5, 2015 at 20:26
  • 3
    @Rinzwind eek. I must protest at this sacrilegious misuse of /usr.
    – muru
    Aug 6, 2015 at 8:35
  • @muru hey it was not MY call >:-D It was a left over from SCO D:
    – Rinzwind
    Aug 6, 2015 at 8:41
  • 1
    Honestly I liked the use of /usr for all things user since that's what it originally meant. What I find these days is the more sacrilegious misuse of /usr/bin as a grand unified dumping ground of all binaries(sys,user,sysop) outside of the base binutils. After all /usr was meant as all things users have access to pulled from a nfs mount while /usr/local was the local user space with /sbin as sysop binaries and /bin system binaries. I get that /home can be a different partition but so can /usr/home/... keeping it in /usr keeps it as user namespace both in policy, implementation, and mindset. Aug 7, 2015 at 14:41
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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .