Understanding PATH Variable Initialization: How /usr/local/bin Gets Added in CentOS 7 Bash Shell


2 views

When examining a fresh CentOS 7 Vagrant box (centos/7), we observe different PATH configurations between regular users and root:

# Vagrant user:
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin

# Root user:
/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

We can trace some components to specific configuration files:

# /etc/profile adds these paths:
if [ "$EUID" = "0" ]; then
    PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
else
    PATH="/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin"
fi

The ~/.bash_profile template from /etc/skel adds user-specific paths:

# /etc/skel/.bash_profile
PATH=$PATH:$HOME/.local/bin:$HOME/bin

The initial PATH setting comes from a less-documented source: the PAM (Pluggable Authentication Modules) environment. Specifically, the file:

# /etc/environment
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

This gets processed before any shell initialization scripts, explaining why we see /usr/local/bin:/usr/bin at the start of the PATH.

The root user's PATH appears different because:

  1. PAM modules may apply different rules for root
  2. /etc/profile modifies the PATH when EUID=0
  3. Root's .bash_profile doesn't include the same user-specific additions

We can trace the PATH construction with this command:

bash -x -l -c 'echo $PATH' 2>&1 | grep PATH=

Sample output showing the initialization sequence:

+ PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
+ PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin

Best practices for modifying PATH in CentOS 7:

# Recommended approach in ~/.bash_profile
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

# Then in ~/.bashrc
export PATH="/custom/path:$PATH"

For permanent system-wide changes, consider these files in order of preference:

  1. /etc/profile.d/custom.sh - Most maintainable
  2. /etc/profile - Traditional location
  3. /etc/environment - Affects all users but limited syntax
# Example /etc/profile.d/custom_path.sh
if [ "$(id -u)" -eq 0 ]; then
    export PATH="/admin/tools:$PATH"
else
    export PATH="/user/tools:$PATH"
fi

Remember that the actual PATH construction involves multiple layers of initialization, and the final result depends on the specific login method (interactive login, non-login shell, etc.).


When examining freshly provisioned CentOS 7 systems, the PATH environment variable shows interesting differences between regular users and root:

# Vagrant user PATH:
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin

# Root user PATH:
/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

Several standard files contribute to PATH configuration:

# /etc/profile snippet:
pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}

# For root:
pathmunge /usr/local/sbin
pathmunge /usr/sbin
pathmunge /sbin
pathmunge /usr/sbin

# For regular users:
pathmunge /usr/local/sbin after
pathmunge /usr/sbin after

The /usr/local/bin entry appears before any profile modifications. This suggests it comes from one of:

  • PAM environment files (/etc/environment)
  • SSH client configuration
  • Login shell initialization files

After investigation, the most likely source is from the /etc/bashrc file, which contains:

# /etc/bashrc snippet:
if [ $UID -gt 199 ] && [ "id -gn" = "id -un" ]; then
    umask 002
else
    umask 022
fi

# Set default PATH
PATH="/usr/local/bin:/usr/bin"

Root's PATH differs because:

  1. The UID check in /etc/bashrc excludes root (UID 0)
  2. /etc/profile adds /usr/local/sbin at the beginning for root
  3. The default PATH for root is built differently

To confirm, we can trace the PATH initialization:

# Add debug output to /etc/bashrc:
echo "DEBUG: Setting default PATH in /etc/bashrc" >&2
PATH="/usr/local/bin:/usr/bin"

# Then login and observe:
vagrant ssh
# Should show the debug message before the PATH is set

To customize the default PATH, you have several options:

# Option 1: Modify /etc/bashrc (affects all users)
sudo sed -i 's|PATH="/usr/local/bin:/usr/bin"|PATH="/custom/path:/usr/local/bin:/usr/bin"|' /etc/bashrc

# Option 2: Create /etc/profile.d/custom_path.sh
echo 'export PATH="/custom/path:$PATH"' | sudo tee /etc/profile.d/custom_path.sh
sudo chmod +x /etc/profile.d/custom_path.sh

# Option 3: User-specific changes in ~/.bash_profile
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bash_profile

When working with PATH in CentOS/RHEL systems:

  • Avoid direct modifications to system files like /etc/bashrc
  • Use /etc/profile.d/ for system-wide changes
  • Remember that changes may require re-login to take effect
  • Test changes in a non-production environment first