How to get $HOME directory when switching to a different user in bash?

Learn how to get $home directory when switching to a different user in bash? with practical examples, diagrams, and best practices. Covers bash development techniques with visual explanations.

Navigating Home: Getting the $HOME Directory After su or sudo

A stylized diagram showing a user switching between different home directories, representing user context changes in a shell.

Understand how to reliably access the correct home directory in Bash when switching users with su or sudo, and avoid common pitfalls.

When working in a Bash environment, especially on multi-user systems, it's common to switch user contexts using commands like su or sudo. A frequent challenge arises when trying to determine the 'home' directory of the new user. While the HOME environment variable usually points to the current user's home directory, its behavior can be nuanced depending on how you switch users and the specific command used. This article explores the reliable methods to get the correct $HOME directory, regardless of the user switching mechanism.

Understanding su and sudo Behavior

The key to understanding how to get the correct home directory lies in how su and sudo handle environment variables. By default, su (without - or --login) and sudo (without -i or --login) often preserve much of the original user's environment, including the HOME variable. This can lead to situations where $HOME still points to the original user's home directory, even after you've successfully switched to a different user ID.

flowchart TD
    A[Start as User A] --> B{Switch User?}
    B -->|Yes, `su userB`| C[Environment Partially Preserved]
    C --> D{`$HOME` still points to User A's home}
    B -->|Yes, `su - userB` or `sudo -i userB`| E[Full Login Shell]
    E --> F{`$HOME` correctly points to User B's home}
    B -->|No| G[Continue as User A]
    D --> H[Need explicit command to get User B's home]
    F --> I[`$HOME` is correct]
    H --> J[e.g., `eval echo ~userB` or `getent passwd userB | cut -d: -f6`]

Behavior of su and sudo on the $HOME environment variable

Reliable Methods to Get the Target User's Home Directory

To ensure you always get the correct home directory for the target user (the user you've switched to or are about to switch to), you should not solely rely on the $HOME environment variable if you suspect a partial environment transfer. Here are several robust methods:

Method 1: Using ~ (Tilde Expansion)

The tilde (~) character in Bash is a powerful shortcut. When used alone, ~ expands to the current user's home directory. When followed by a username, e.g., ~username, it expands to that specific user's home directory. This expansion happens before the command is executed and is generally reliable.

# As userA, switch to userB without a full login shell
su userB

# Inside userB's shell (but with userA's HOME variable potentially)
# This will correctly show userB's home directory
echo ~userB

# This will show the current user's home, which might be userA's if not a login shell
echo $HOME

# To get the current user's home reliably, even if $HOME is wrong
echo ~

Using tilde expansion to get a user's home directory

Method 2: Querying /etc/passwd with getent

The /etc/passwd file (or its equivalent via NSS, which getent uses) stores user account information, including their home directory. You can query this file directly to get the home directory for any user on the system. This is the most programmatic and reliable way to get a user's home directory, independent of the current shell's environment.

# Get the home directory for 'userB'
getent passwd userB | cut -d: -f6

# Get the home directory for the current effective user
getent passwd "$(whoami)" | cut -d: -f6

Using getent and cut to extract home directory from passwd entry

Method 3: Using sudo -H or sudo -i for Commands

If you are running a single command as another user via sudo, you can use sudo -H to set the HOME environment variable to the target user's home directory for that specific command. Alternatively, sudo -i provides a full login shell, ensuring $HOME is correctly set.

# Run a command as 'userB' with userB's HOME directory set
sudo -H -u userB bash -c 'echo $HOME'

# Run a command as 'userB' with a full login environment
sudo -i -u userB bash -c 'echo $HOME'

# If you just want to see userB's home without switching
sudo -u userB printenv HOME

# Or more directly, using the tilde expansion within sudo
sudo -u userB bash -c 'echo ~'

Using sudo -H or sudo -i to ensure correct HOME for commands