Home Directory and ~ Shortcuts
Every user account on a Linux system has a home directory — a personal corner of the filesystem where that user’s files, downloads, shell configuration, and application settings normally live. Bash gives you a fast shortcut to it: the tilde (~) character, along with the $HOME environment variable. Once you understand how tilde expansion actually works, you’ll stop typing long paths, write more portable scripts, and avoid a handful of surprisingly common mistakes involving quoting and sudo.
Overview: How the Home Directory Works
For a regular user, the home directory is almost always /home/username — for example /home/alice. The root superuser is the one common exception: root’s home directory is /root, not /home/root. This isn’t arbitrary — keeping root’s files directly under / means an administrator can still log in and have a usable home directory even if /home lives on a separate disk partition that fails to mount, or during a rescue boot before other filesystems are available.
Where a user’s home directory actually points is recorded in /etc/passwd, the system’s user database. Each line has seven colon-separated fields: username, password placeholder, user ID, group ID, a comment field, the home directory path, and the login shell. The sixth field is what the system treats as “home” for that account. When an administrator creates a new account with sudo useradd -m newuser, the -m flag tells useradd to create that home directory and populate it with starter files copied from /etc/skel (dotfiles like .bashrc and .profile). That’s why a freshly created account already has a working shell configuration the very first time you log in.
At login, Bash reads the home directory field for your account and stores it in the environment variable $HOME. From that point on, every program — not just the shell — can ask “where is this user’s home?” by reading $HOME, instead of guessing a path or having one hardcoded. That’s what makes $HOME more reliable than typing /home/alice directly: it’s correct no matter which account happens to be logged in.
The tilde character ~ is a convenience Bash builds on top of $HOME, called tilde expansion. It’s important to understand that ~ is not something cd, ls, or any other program understands directly — Bash performs a purely textual substitution on the word before the command ever runs. When Bash sees a word starting with ~, it replaces that word with a real path before the command sees its arguments at all. A bare ~ (followed by nothing or a /) is replaced with the value of $HOME. A ~ followed immediately by a username, like ~mia, is replaced with that user’s home directory, looked up from /etc/passwd — this lookup succeeds even if you don’t have permission to actually enter that directory; permission is checked separately, later, when the command tries to use the path.
Finally, cd with no arguments at all is shorthand for cd ~, which is shorthand for cd "$HOME". All three do exactly the same thing: change the current working directory to the value of $HOME.
Syntax
Bash recognizes several tilde forms, all expanded before the command runs:
| Form | Expands to |
|---|---|
~ |
Value of $HOME (the current user’s home directory) |
~/path |
$HOME followed by /path, e.g. ~/backups |
~username |
The home directory of username, looked up in /etc/passwd |
~+ |
Value of $PWD — the current working directory |
~- |
Value of $OLDPWD — the previous working directory |
$HOME |
The home directory, via explicit variable expansion instead of tilde expansion |
cd |
With no arguments, changes to $HOME |
Shown as an abstract pattern rather than a runnable example, the general forms look like this:
~
~username
~+
~-
$HOME
Examples
Example 1: Jump home from anywhere
No matter how deep you’ve navigated, cd ~ (or plain cd) always takes you straight back home.
cd /var/log
cd ~
pwd
Output:
/home/alice
The first cd moves into /var/log. The second, cd ~, has its argument expanded by Bash to /home/alice before cd even runs, so it jumps straight home. pwd then confirms the current directory.
Example 2: Using $HOME inside a command
$HOME works anywhere a path is expected, including inside larger expressions built with command substitution.
mkdir -p "$HOME/backups"
cp "$HOME/.bashrc" "$HOME/backups/bashrc-$(date +%F)"
ls "$HOME/backups"
Output:
bashrc-2026-08-04
The first line creates a backups directory inside the home directory (-p avoids an error if it already exists). The second copies .bashrc into it, appending today’s date from $(date +%F) to the filename. Every expansion here is quoted, which matters if $HOME ever contained a space.
Example 3: Quick-switching with ~- and ~+
~- and ~+ let you bounce between directories without retyping full paths.
cd /etc
cd /var/www
cd ~-
pwd
Output:
/etc
Each cd updates two things: $PWD (the new current directory) and $OLDPWD (whatever the previous directory was). After cd /etc then cd /var/www, $OLDPWD holds /etc. cd ~- expands to cd "$OLDPWD", so it jumps back to /etc. Running cd ~+ instead would expand to cd "$PWD" — a no-op that leaves you exactly where you are.
How It Works Step by Step
When Bash reads a command line, it processes it through several expansion stages, in a fixed order, before anything actually runs: brace expansion, tilde expansion, parameter and variable expansion ($HOME, $1, and so on), command substitution ($(...)), arithmetic expansion, word splitting, and finally pathname (glob) expansion. Tilde expansion happens early, and only applies to an unquoted word that begins with ~ — specifically at the very start of a word, or right after a : or = in certain assignment-like contexts (which is why something like PATH=~/bin:$PATH still works, even though it looks like a plain assignment rather than a bare argument).
Concretely, for cd ~/projects, Bash first tokenizes the line into the words cd and ~/projects. It sees the second word starts with ~, strips the leading ~, and checks what follows: nothing before the /, so it substitutes the value of $HOME. The word becomes, say, /home/alice/projects. Only after this substitution does Bash actually invoke the cd builtin, passing it the already-expanded, literal path. cd itself never sees a ~ character at all — as far as it’s concerned, you typed the full path yourself.
For ~username, the mechanism is the same except Bash looks up that user’s home directory from the system’s user database (/etc/passwd) instead of reading $HOME. If no such user exists, Bash leaves the word untouched — ~doesnotexist expands to the literal string ~doesnotexist, which is why a typo’d username produces a confusing “no such file or directory” rather than a clear error about the tilde itself.
Common Mistakes
Mistake 1: Quoting the tilde disables expansion
Tilde expansion only happens on an unquoted word. The moment you wrap ~ in single or double quotes, Bash treats it as a literal character instead of a shortcut for $HOME.
find "~/projects" -name "*.log"
Output:
find: '~/projects': No such file or directory
Bash never expanded ~ here because it was inside the double quotes, so find literally searched for a directory named ~ in the current folder. Leave the tilde itself outside the quotes — you can still quote the rest of the pattern safely:
find ~/projects -name "*.log"
Mistake 2: Expecting sudo to change what $HOME means
People often assume that prefixing a command with sudo makes any ~ or $HOME in it resolve against root’s home directory. It doesn’t, because your own shell expands unquoted $HOME before sudo ever runs.
sudo echo $HOME
Output:
/home/alice
Your login shell substitutes $HOME with your own home directory first, so sudo actually receives the already-expanded command echo /home/alice — it just runs echo as root, printing your path, not root’s. To see the expansion happen inside the elevated shell instead, defer it:
sudo bash -c 'echo $HOME'
Output:
/root
Because $HOME is inside single quotes, your shell never touches it; it’s bash -c running as root that expands $HOME, this time to /root.
Mistake 3: Hardcoding a path instead of using $HOME
A script that hardcodes a specific user’s home directory only works for that one user.
#!/usr/bin/env bash
cp report.csv /home/alice/reports/
This copies the file correctly when Alice runs it, but breaks the moment anyone else runs the same script, or it runs under a different account via cron or CI. Use $HOME so the script works for whoever runs it:
#!/usr/bin/env bash
cp report.csv "$HOME/reports/"
Best Practices
- Use
~or$HOMEinstead of a hardcoded/home/usernamepath in scripts, so the same script works for any user. - Always quote variable expansions like
"$HOME/reports"in scripts, even though the leading tilde itself must stay unquoted to expand. - Use plain
cdwith no arguments as the fastest way back to your home directory. - Remember
~-and~+to jump back to your previous or current directory without retyping full paths. - If you need root’s
$HOMEspecifically, usesudo -ior defer the expansion inside the sudo’d shell (sudo bash -c '...') rather than assuming a baresudo command ~/pathresolves against root. - Keep your home directory’s permissions private (the typical default of
750or700), since it usually holds SSH keys, shell history, and configuration files other users shouldn’t read.
Practice Exercises
- From
/var/log, return to your home directory using the shortest command you can, then confirm your location withpwd. - Write a single command that backs up
~/.bashrcto~/.bashrc.bakwithout typing your username anywhere. - Run
cd /etc, thencd /tmp, then predict whatcd ~-will print before you runpwdto check — then trycd ~+and predict again.
Summary
- Every account has a home directory, recorded in
/etc/passwdand exposed to the shell as$HOME. ~is Bash tilde expansion, a text substitution performed before a command runs — it is not understood bycd,ls, or any other program directly.~alone expands to$HOME;~usernameexpands to that user’s home;~+and~-expand to$PWDand$OLDPWD.cdwith no arguments is shorthand forcd ~.- Tilde expansion never happens inside quotes — quoting
"~/path"turns it into a literal string. sudo command ~/pathresolves~against your own$HOME, not root’s, because expansion happens in your shell beforesudoruns.- Prefer
$HOME/~over hardcoded/home/usernamepaths in scripts for portability.
