Every interactive shell session on RHEL 8 is governed by a chain of startup scripts that define environment variables, aliases, functions, and the prompt. Understanding which file is loaded and when prevents confusion around why a variable set in one terminal disappears in another, or why a cron job cannot find a command that works interactively. This tutorial covers the purpose and load order of ~/.bashrc, ~/.bash_profile, and /etc/profile.d/, and shows how to configure persistent environment variables for a single user or for all users on the system.

Prerequisites

  • A running RHEL 8 system with a standard user account
  • Basic familiarity with the Bash shell
  • A terminal text editor such as vi, nano, or vim

Step 1 — Understanding Startup File Load Order

Bash distinguishes between login shells (SSH sessions, su -, console logins) and non-login interactive shells (opening a terminal in a desktop session, running bash inside an existing shell). Login shells source ~/.bash_profile; non-login interactive shells source ~/.bashrc. The conventional pattern is to have ~/.bash_profile source ~/.bashrc so settings apply everywhere.

# Login shell load order:
# 1. /etc/profile
# 2. /etc/profile.d/*.sh  (sourced by /etc/profile)
# 3. ~/.bash_profile  (or ~/.bash_login, then ~/.profile)

# Non-login interactive shell:
# 1. ~/.bashrc

# Make ~/.bash_profile always load ~/.bashrc (if not already present)
grep -q '.bashrc' ~/.bash_profile || echo '[[ -f ~/.bashrc ]] && source ~/.bashrc' >> ~/.bash_profile

Step 2 — Setting and Exporting Environment Variables

Variables defined without export are local to the current shell and invisible to child processes. Always export variables that need to be inherited by scripts or applications you launch. Add persistent per-user exports to ~/.bashrc.

# Temporary export (current session only)
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
export PATH="$JAVA_HOME/bin:$PATH"

# Persistent per-user — add to ~/.bashrc
echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk' >> ~/.bashrc
echo 'export PATH="$JAVA_HOME/bin:$PATH"' >> ~/.bashrc

# Reload without logging out
source ~/.bashrc

# Verify
echo $JAVA_HOME
printenv JAVA_HOME

Step 3 — Defining Aliases

Aliases are short command shortcuts that exist only in interactive shells. Define them in ~/.bashrc so they are available every time you open a terminal. Avoid shadowing system commands with the same name; prefix with a backslash (command) in scripts to bypass an alias.

# Add aliases to ~/.bashrc
cat >> ~/.bashrc <<'EOF'

# Personal aliases
alias ll='ls -lah --color=auto'
alias grep='grep --color=auto'
alias ..='cd ..'
alias ...='cd ../..'
alias update='sudo dnf update -y'
alias syslog='sudo journalctl -xe'
EOF

# Reload
source ~/.bashrc

# Verify an alias
alias ll

Step 4 — Customizing the PS1 Prompt

The PS1 variable controls the primary shell prompt. RHEL 8’s default prompt shows the username, hostname, and current directory. You can enrich it with color codes and additional information such as the exit code of the last command or the current Git branch.

# Add a colored prompt to ~/.bashrc
cat >> ~/.bashrc <<'EOF'

# Custom PS1: green user@host, blue path, red $ if last command failed
PS1='[e[32m]u@h[e[0m]:[e[34m]w[e[0m]$ '
EOF

source ~/.bashrc

# Display current PS1 value
echo "$PS1"

Step 5 — System-wide Variables via /etc/profile.d/

To apply environment settings to every user on the system, place a .sh script in /etc/profile.d/. This directory is sourced by /etc/profile during login shell initialization. This is the correct place for variables that tools like ansible, java, or custom applications need system-wide.

# Create a system-wide environment file
sudo tee /etc/profile.d/custom_env.sh <<'EOF'
# System-wide custom environment variables
export APP_ENV=production
export APP_LOG_DIR=/var/log/myapp
export PATH="/opt/custom/bin:$PATH"
EOF

# Must be readable by all users
sudo chmod 644 /etc/profile.d/custom_env.sh

# Verify (takes effect on next login; force-test now)
source /etc/profile.d/custom_env.sh
printenv APP_ENV

Step 6 — Inspecting the Runtime Environment

Use printenv to display a single variable or the full environment, and env to list all exported variables. The env command can also run a program with a clean or modified environment, which is useful for debugging whether a script depends on a particular variable.

# Print a single variable
printenv PATH

# Print all exported variables
printenv

# List all environment variables (similar to printenv)
env

# Run a command with a clean environment
env -i PATH=/usr/bin:/bin bash --norc -c 'echo $PATH'

# Run a command with one variable overridden
env APP_ENV=staging /opt/myapp/start.sh

Conclusion

You now understand the Bash startup file hierarchy on RHEL 8, know how to set persistent per-user and system-wide environment variables, define aliases, customize the PS1 prompt, and inspect the runtime environment with printenv and env. Keeping these settings in the correct files ensures consistent, reproducible shell environments across logins and users.

Next steps: How to Use tmux for Terminal Multiplexing on RHEL 8, How to Configure sudo and Sudoers on RHEL 8, and How to Write Bash Scripts on RHEL 8.