35.5 /etc/profile and /etc/profile.d: Login Shell Initialization
Alright, let’s talk about the big guns: /etc/profile and its sidekick directory, /etc/profile.d/. This is where system-wide shell configuration kicks off for login shells. Think of this as the town square announcement that happens every single time you, or any other user, properly log in.
Now, why should you care? Because this is where your operating system or your overzealous sysadmin sets the stage. It’s where global PATH variables are set, where environment variables that every application might need (think JAVA_HOME, EDITOR) are defined, and where umask values are enforced. It runs for every user on a login, making it incredibly powerful and, consequently, a fantastic way to break everyone’s system if you edit it carelessly. No pressure.
The Order of Operations (or, How Your Shell Gets Dressed)
Before we dive into the files, you need to understand the sequence. When you log in (think: SSH session, sudo login, or a console tty), your shell is a “login shell.” Its startup ritual is meticulous:
/etc/profileis sourced first. This is the system-wide master file.- It then looks inside
/etc/profile.d/and sources every single.shfile it finds there, in alphabetical order. This is the smarter, more modular way to do things. - After that, it goes looking for the user’s personal config files (
~/.bash_profile,~/.profile, etc.).
The key takeaway? /etc/profile runs before your personal files. So, if /etc/profile sets PATH=/usr/bin, your ~/.bash_profile can only append to it (PATH=$PATH:/my/fancy/bin), not easily override it. This hierarchy is intentional; system policy trumps user preference.
Inside the Belly of the Beast: /etc/profile
If you cat /etc/profile on something like a CentOS or Ubuntu system, you’ll see what looks like a very cautious shell script. It’s usually checking what shell you’re running, setting up the PATH based on who you are (regular user vs. root), reading in your locale settings, and then, crucially, kicking off the next part.
# A typical chunk you might see in /etc/profile
if [ -d /etc/profile.d ]; then
for i in /etc/profile.d/*.sh; do
if [ -r $i ]; then
. $i
fi
done
unset i
fi
This elegant little loop is the workhorse. It says: “If the directory /etc/profile.d exists, then for every file ending in .sh inside it, if the file is readable, source it.” The unset i at the end is a hallmark of good, clean scripting—it cleans up the loop variable so it doesn’t pollute the global environment. Someone was thinking.
The Sane Way: /etc/profile.d/
This directory is a godsend. Instead of forcing us all to edit a single monolithic /etc/profile file (a surefire way to cause merge conflicts and headaches), package managers (rpm, dpkg) can just drop a new file into /etc/profile.d/ to set up environments for their specific applications.
Need to add a new directory to every user’s PATH for a custom app? Don’t touch /etc/profile. Just create a new file, e.g., /etc/profile.d/myapp.sh.
# /etc/profile.d/z_myapp.sh
# I prefix with 'z_' to ensure it runs last, after other PATH additions
PATH="$PATH:/opt/myapp/bin"
export PATH
Want to set a default editor for all users, forcing your pro-Vim agenda upon the masses? Easy.
# /etc/profile.d/editor.sh
export EDITOR=/usr/bin/vim
The best practice here is to leave /etc/profile alone. Do your system-wide customizations in /etc/profile.d/. It’s modular, it’s safer, and it’s how the system expects to be managed.
The Gotchas and The Glory
Here’s where the “brilliant friend” part comes in with some harsh truths.
- It’s for Login Shells Only: Remember, this only runs for login shells. If you open a new terminal window in your GUI desktop environment, it’s probably a non-login interactive shell. It won’t source
/etc/profile. It will source/etc/bash.bashrcor similar. This distinction trips up everyone. Always test your changes by doing a proper login (ssh localhostis a good test). - Alphabetical Order is Law: The files in
profile.dare sourced in alphabetical order. Ifa_env.shsetsPATH=/fooandb_env.shsetsPATH=/bar, your finalPATHwill be/bar, obliterating the previous setting. If your scripts depend on each other, name them carefully (e.g.,01_base.sh,02_apps.sh). - Syntax Errors are Catastrophic: A syntax error in any of these files can prevent any user from logging in. It’s a nightmare. Always, always test your scripts with
bash -n /path/to/script.shto check for syntax errors before you save them to/etc/profile.d/. - It’s Sourced, Not Executed: These files are sourced (using the
.orsourcecommand), meaning they run in the current shell’s context. They don’t get their own subshell. This is why they can export variables that persist. Don’t try toexitfrom inside one, or you’ll log the user out instantly. Yes, it’s as funny as it sounds (for everyone else).