Why are bash aliases defined in `/etc/profile.d/` scripts?

Hi all, I’m a long-time Fedora and RedHat/RHEL/CentOS user but this is my first post here. And apologies if this topic has been discussed before, I tried to look up some history but didn’t find anything.

As per title, why are bash aliases defined in /etc/profile.d scripts?
Specifically for bash (I’m not too familiar with other shells), aliases are not inherited by sub-shells. Which I guess is the reason behind /etc/bashrc sourcing the profile scripts in interactive, non-login shells. That kinda defeats the purpose of profiles scripts which in bash, as far as I understand, are meant to only be sourced for login shells. And that in turn leads to having to make profile.d scripts idempotent, while they shouldn’t need that extra complication.

Not that anything doesn’t work out of the box, but recently I saw an environment where a non-idempotent script was added to /etc/profile.d/ to set default values for env variables (which seems to be what profile scripts are meant to do). That caused some hard to debug issues with those vars being stomped over in sub-shells, and I was surprised to notice that all profile scripts are re-sourced in non-login shells.
That actually happened in a downstream distro, but since Fedora is upstream of all RH-related distros I thought I could ask here.

At a first glance, this looks quite strange. Naively I would think that aliases should be added to bashrc, and to provide convenience to packages they could be organized in separate scripts in an /etc/bashrc.d/ directory so that /etc/bashrc could source those instead of the scripts in /etc/profile.d. Then profile scripts could just be profile scripts, not have to be idempotent, everything would be more straightforward, and bash would be happy.

But I’m sure I’m missing something as this goes way back in older versions! Does anyone have more historical context?

/etc/bashrc is owned by setup. You can see the changelog in its spec. That changelog dates back to 1997, but the git repo history only goes to 2008. Early in that history (still in 2008), there was a commit that made profile.d scripts be sourced in all non-login shells, not just interactive ones.

I happen to have Red Hat Linux 7.2 (from 2001) installed in a VM, and while /etc/bashrc looks rather different, the behavior is similar to just before that 2008 change (only source profile.d in interactive non-login shells).

The setup changelog mentions that /etc/bashrc was moved from bash earlier in 2001. From downloaded bash SRPMs, I can say that sourcing profile.d was added to that file between RHL 6.2 and 7.0. Prior to that, it was basically empty.

In RHL 7.2, there are two scripts that set aliases: colorls.sh and which-2.sh. Here are excerpts from the changelog entries introducing those files:

* Wed Nov 17 1999 Bernhard Rosenkraenzer <bero@redhat.com>
- Add colorls.sh/colorls.csh to /etc/profile.d
  (Newbies are likely to like them, professionals who don't will know
  how to remove them. Also, they're compatible with DLD)
[...]
* Fri Sep 24 1999 Carlo Wood <carlo@gnu.org>
- There should not be a reason anymore to include README.alias in the rpm docs.
[...]
- Added /etc/profile.d for automatic alias inclusion.

That pretty much covers when, but I’m still not clear on why; the bash changelog is pretty vague. profile.d was an existing mechanism at the time, so maybe repurposing it was judged easier than creating something new like bashrc.d. It all seems very messy though.

1 Like

Fedora 39

# /etc/bashrc

# System wide functions and aliases
# Environment stuff goes in /etc/profile

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

# Prevent doublesourcing
if [ -z "$BASHRCSOURCED" ]; then
  BASHRCSOURCED="Y"

I think this is the point of the config.d folders:
# will prevent the need for merging in future updates.

I also think the idea was to strip down new/more config paths. To keep old-timers have the overview and simplify for newcomers :slight_smile: