SysTutorials

Getting a User’s Home Directory in Bash

· updated April 12, 2026

The tilde expansion ~username works fine when the username is literal, but fails when the username is stored in a variable like ~$user. Bash doesn’t perform tilde expansion on variables by default—it only expands ~ at the beginning of a word before variable expansion happens.

Using eval

The most common approach is to use eval:

user="alice"
userhome=$(eval echo ~$user)
echo "$userhome"  # Output: /home/alice

The eval forces a re-evaluation of the string, allowing the tilde expansion to occur after variable substitution. However, eval has security implications if the variable comes from untrusted input, since it executes arbitrary code.

A safer and more portable approach is to query the system’s user database directly with getent:

user="alice"
userhome=$(getent passwd "$user" | cut -d: -f6)
echo "$userhome"  # Output: /home/alice

This method:

Checking if the User Exists

getent returns nothing if the user doesn’t exist, so you can validate:

user="alice"
if userhome=$(getent passwd "$user" | cut -d: -f6); then
    echo "Home directory: $userhome"
else
    echo "User '$user' not found" >&2
    exit 1
fi

Using Parameter Expansion with eval

If you prefer eval but want to be more explicit:

user="alice"
userhome=$(eval echo "~${user}")

The quotes ensure the variable is expanded safely. Still use this only with trusted input.

Using HOME Variable as Fallback

For the current user, just reference the $HOME variable directly:

echo "$HOME"  # Current user's home

For other users, stick with getent.

Performance Consideration

If you’re calling this repeatedly in a loop, getent is slightly faster than eval echo since it’s a single system call rather than spawning a subshell:

# Good for loops
for user in alice bob charlie; do
    home=$(getent passwd "$user" | cut -d: -f6)
    [[ -n "$home" ]] && echo "$user: $home"
done

Summary

The getent approach is the modern standard across sysadmin practices and handles edge cases like centralized authentication better than tilde expansion.

Practical Tips and Common Gotchas

When working with programming languages on Linux, environment management is crucial. Use version managers like asdf, pyenv, or sdkman to handle multiple language versions without system-wide conflicts. Always pin dependency versions in production to prevent unexpected breakage from upstream changes.

For build automation, modern alternatives often outperform traditional tools. Consider using just or task instead of Make for simpler task definitions. Use containerized build environments to ensure reproducibility across different development machines.

Debugging Strategies

Start with the simplest debugging approach and escalate as needed. Print statements and logging often reveal the issue faster than attaching a debugger. For complex issues, use language-specific debuggers like gdb for C and C++, jdb for Java, or dlv for Go. Always check error messages carefully before diving into code.

Quick Verification

After applying the changes described above, verify that everything works as expected. Run the relevant commands to confirm the new configuration is active. Check system logs for any errors or warnings that might indicate problems. If something does not work as expected, review the steps carefully and consult the official documentation for your specific version.

← All posts