Understanding the Key Difference Between `su` vs `su -` in CentOS/RHEL: Environment Variables and PATH Resolution


10 views


When administering CentOS/RHEL systems, many administrators encounter a puzzling scenario:


$ su
Password: 
# ifconfig
bash: ifconfig: command not found
# exit

$ su -
Password: 
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500

The critical difference lies in how environment variables are handled:

  • su: Preserves the original user's environment (shell variables, PATH, etc.)
  • su - or su -l: Simulates a full login, loading the target user's environment

Let's examine the PATH differences with concrete examples:


# As regular user
$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

# After 'su' without hyphen
$ su
# echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin  # Same as original user

# After 'su -'
$ su -
# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin  # Root's default PATH

The environment difference stems from these critical files:


/etc/profile
/etc/bashrc
~/.bash_profile
~/.bashrc

When using su -, the system reads all these files sequentially, while plain su only processes:


/etc/bashrc
~/.bashrc

Consider these real-world scenarios:


# Dangerous scenario with plain 'su'
$ su
# rm -rf /tmp/some_dir/*  # If PATH compromised, 'rm' could be aliased/malicious

# Safe alternative
$ su -
# rm -rf /tmp/some_dir/*  # Uses root's clean environment
  • Always prefer sudo for single commands when possible
  • Use su - when needing full root environment
  • For scripting: su -c 'command' - root provides proper environment

When debugging environment problems:


# Compare environments
$ su -c 'env | sort > /tmp/root_env'
$ env | sort > /tmp/user_env
$ diff /tmp/user_env /tmp/root_env


When you execute su to become root in CentOS, you might encounter unexpected behavior like this:

$ su
Password: 
# ifconfig
bash: ifconfig: command not found

Yet when you use su -, everything works:

$ su -
Password: 
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.100  netmask 255.255.255.0  broadcast 192.168.1.255

The fundamental difference lies in how environment variables are handled:

  • su: Maintains the original user's environment (PATH, HOME, etc.)
  • su - or su -l: Starts a login shell with root's environment

You can verify this by checking environment variables after each command:

$ su
# echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

$ su -
# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

This behavior affects several common scenarios:

  1. System binaries access: /sbin and /usr/sbin aren't in regular users' PATH
  2. Configuration files: ~/.bashrc and ~/.profile aren't sourced with plain su
  3. Service management: Commands like systemctl might behave differently

For scripting purposes, always explicitly specify which version you need:

#!/bin/bash
# For full root environment
su - root -c "/sbin/ifconfig eth0 down"

# For minimal environment change
su root -c "echo \$PATH"

While su - provides more complete root functionality, it also:

  • Loads root's shell configuration files (potential security risk if modified)
  • Changes the working directory to /root
  • Makes environment changes that might affect script behavior

For automated tasks, consider using sudo instead for better auditing:

sudo /sbin/ifconfig eth0 down

The distinction dates back to original Unix implementations where:

  • su was designed for quick privilege escalation
  • su - was meant for full login sessions

In modern practice, many administrators prefer sudo -i as an alternative:

sudo -i
# Equivalent to su - but with sudo's audit trail