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 $HOME instead of a hardcoded /home/username path 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 cd with 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 $HOME specifically, use sudo -i or defer the expansion inside the sudo’d shell (sudo bash -c '...') rather than assuming a bare sudo command ~/path resolves against root.
  • Keep your home directory’s permissions private (the typical default of 750 or 700), since it usually holds SSH keys, shell history, and configuration files other users shouldn’t read.

Practice Exercises

  1. From /var/log, return to your home directory using the shortest command you can, then confirm your location with pwd.
  2. Write a single command that backs up ~/.bashrc to ~/.bashrc.bak without typing your username anywhere.
  3. Run cd /etc, then cd /tmp, then predict what cd ~- will print before you run pwd to check — then try cd ~+ and predict again.

Summary

  • Every account has a home directory, recorded in /etc/passwd and exposed to the shell as $HOME.
  • ~ is Bash tilde expansion, a text substitution performed before a command runs — it is not understood by cd, ls, or any other program directly.
  • ~ alone expands to $HOME; ~username expands to that user’s home; ~+ and ~- expand to $PWD and $OLDPWD.
  • cd with no arguments is shorthand for cd ~.
  • Tilde expansion never happens inside quotes — quoting "~/path" turns it into a literal string.
  • sudo command ~/path resolves ~ against your own $HOME, not root’s, because expansion happens in your shell before sudo runs.
  • Prefer $HOME/~ over hardcoded /home/username paths in scripts for portability.