123

First off, I know that ~/ is the home directory. CDing to ~ or ~/ takes me to the home directory.

However, cd ~X takes me to a special place, where X seems to be anything.

In bash, if I hit "cd ~" and hit tab, it shows a bunch of possible ~X options like ~mail and ~postgres and ~ssh. Going to those folders and doing a pwd shows me that these folders are not in the home directory; they're all over the place.

They are not aliases. I've checked. They're not env. variables, or else they'd require a $.

What is setting these links, and where can I find where these are being set?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
jbu
  • 15,831
  • 29
  • 82
  • 105
  • ~X simply returns the literal "~X" but ~ returns $HOME and ~+ returns $PWD - they are not special other than that they fetch shell variables. i.e. they do not store the values or execute a command to look them up. They are already defined. Have you tried ~- ? I can't think of a use for it, but again, it returns a shell variable $OLDPWD – SDsolar Jul 31 '17 at 02:00

8 Answers8

89

It's a Bash feature called "tilde expansion". It's a function of the shell, not the OS. You'll get different behavior with csh, for example.

To answer your question about where the information comes from: your home directory comes from the variable $HOME (no matter what you store there), while other user's homes are retrieved real-time using getpwent(). This function is usually controlled by NSS; so by default values are pulled out of /etc/passwd, though it can be configured to retrieve the information using any source desired, such as NIS, LDAP or an SQL database.

Tilde expansion is more than home directory lookup. Here's a summary:

~              $HOME
~fred          (freds home dir)

~+             $PWD       (your current working directory)
~-             $OLDPWD    (your previous directory)
~1             `dirs +1`
~2             `dirs +2`
~-1            `dirs -1`

dirs and ~1, ~-1, etc., are used in conjunction with pushd and popd.

Edited to add:

As Sean Bright pointed out in a comment, the baseline tilde behavior regarding home directories is codified as standard behavior for POSIX-compliant shells. Additionally, the wordexp() C API function is specified to implement this behavior. Though, obviously, use with caution.

tylerl
  • 30,197
  • 13
  • 80
  • 113
  • as a note [tag:fish] doesn't support any of them except the plain tilde (~) –  Feb 18 '17 at 10:03
  • 1
    why they came up with `~+`? seems rather useless. – cregox May 11 '17 at 09:06
  • 4
    ~+ is roughly the same as . However, to use something like ./file it has to go to the file system and figure out where . is located - it takes a few cycles. Using ~+ saves it the work by simply returning the contents of the shell variable $PWD which is already defined as you traverse the file system. – SDsolar Jul 31 '17 at 02:02
  • The `~` and `~username` forms are [specified by POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_01), so it's not specifically a bash thing. It may have been added to POSIX since this answer was written though. – Sean Bright Feb 03 '22 at 15:37
  • @SeanBright Fair enough; my point was that it was a shell thing, and different shells do different things. And other non-shell things (like GUIs or other programs) may do nothing at all. POSIX, after all, is just a standard saying "please implement these features in your stuff." But you're right, it's worth pointing out the standards involved. – tylerl Feb 04 '22 at 17:29
  • You can add `=~`when doing string comparison in a test. – Timo Mar 31 '22 at 12:05
36

Those are the home directories of the users. Try cd ~(your username), for example.

Sam
  • 7,252
  • 16
  • 46
  • 65
Ana Betts
  • 73,868
  • 16
  • 141
  • 209
19

Are they the home directories of users in /etc/passwd? Services like postgres, sendmail, apache, etc., create system users that have home directories just like normal users.

Sean Bright
  • 118,630
  • 17
  • 138
  • 146
15

Those are users. Check your /etc/passwd.

cd ~username takes you to that user's home directory.

Aulis Ronkainen
  • 164
  • 2
  • 4
  • 12
Joakim Elofsson
  • 36,326
  • 1
  • 22
  • 28
  • FTW. Upvote. TNX for clearing that up. I wonder how many cycles and perhaps even a subshell are involved in that one. Just imagine if your system has 3K users, like at a small ISP. Yikes. – SDsolar Jul 31 '17 at 02:05
10

On my machine, because of the way I have things set up, doing:

cd ~             # /work1/jleffler
cd ~jleffler     # /u/jleffler

The first pays attention to the value of environment variable $HOME; I deliberately set my $HOME to a local file system instead of an NFS-mounted file system. The second reads from the password file (approximately; NIS complicates things a bit) and finds that the password file says my home directory is /u/jleffler and changes to that directory.

The annoying stuff is that most software behaves as above (and the POSIX specification for the shell requires this behaviour). I use some software (and I don't have much choice about using it) that treats the information from the password file as the current value of $HOME, which is wrong.

Applying this to the question - as others have pointed out, 'cd ~x' goes to the home directory of user 'x', and more generally, whenever tilde expansion is done, ~x means the home directory of user 'x' (and it is an error if user 'x' does not exist).


It might be worth mentioning that:

cd ~-       # Change to previous directory ($OLDPWD)
cd ~+       # Change to current directory ($PWD)

I can't immediately find a use for '~+', unless you do some weird stuff with moving symlinks in the path leading to the current directory.

You can also do:

cd -

That means the same as ~-.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    About `cd ~+`: you could potentially use it to check if a directory you're currently in still exists - even if it is a pretty unorthodox way of doing so. – professorsloth Mar 20 '13 at 08:52
5

Tilde expansion in Bash:

http://bash-hackers.org/wiki/doku.php/syntax/expansion/tilde

TheBonsai
  • 15,513
  • 4
  • 22
  • 14
1

If you're using autofs then the expansion might actually be coming from /etc/auto.home (or similar for your distro). For example, my /etc/auto.master looks like:

/home2 auto.home --timeout 60

and /etc/auto.home looks like:

mgalgs -rw,noquota,intr space:/space/mgalgs
mgalgs
  • 15,671
  • 11
  • 61
  • 74
0

It's possible you're seeing OpenDirectory/ActiveDirectory/LDAP users "automounted" into your home directory.

In *nix, ~ will resolve to your home directory. Likewise ~X will resolve to 'user X'.

Similar to automount for directories, OpenDirectory/ActiveDirectory/LDAP is used in larger/corporate environments to automount user directories. These users may be actual people or they can be machine accounts created to provide various features.

If you type ~Tab you'll see a list of the users on your machine.

JS.
  • 14,781
  • 13
  • 63
  • 75