Site icon GetPageSpeed

CentOS/RHEL: where is my PATH?

Varnish CLI commands

Varnish CLI commands

The PATH environment variable

For those unfamiliarly with what it is. The PATH environment variable controls which directories are being checked when you are attempting to run a program.
In other words, it helps construct the complete path to the program while searching for it across the specific directories.
Separated by a semicolon, the directories are listed in this variable’s value in the order of priority, with priority decreasing from left (highest) to the right (lowest) e.g.

PATH=/usr/local/bin:/usr/bin

The PATH customization per user

A Linux OS user can set up their own, user-specified PATH. This allows to easily launch user-installed programs. And to give priority between running different versions of the same program.

While doing my writeup on Faster PHP CLI and Cron Jobs, I have found quite a few inconsistencies about where you put the PATH environment variable customization for a user. Specifically for CentOS/RHEL systems.

Would you customize your PATH in the ~/.bashrc or ~/.bash_profile files?
And what it should be customized to initially?

&tldr; Scroll down to “The solution-workaround” section

The right ways:

Unfortunately, none of this applies to CentOS/RHEL 7 and 8. Here’s why and what to do about it.

The defaults are quite different between CentOS/RHEL 7 and 8.

How CentOS 7 does it (wrong)

A new user gets PATH added to ~/.bash_profile and it’s set to

PATH=$PATH:$HOME/.local/bin:$HOME/bin

So initially it is /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/home/foo/.local/bin:/home/foo/bin

Setting PATH in ~/.bash_profile is correct because it prevents “double-sourcing” PATH. If it was put to ~/.bashrc, running subshell, e.g. echo $(command), would source the file many times, and this would result in a lengthy PATH with duplicate directories for the subshells.

However, $PATH:$HOME/.local/bin:$HOME/bin is not good in case we want to override system programs with user’s installed programs or custom wrappers, like in the Faster PHP CLI and Cron Jobs.

But the other “bad” thing, if you will, is that running non-interactive commands over SSH, will not include our user-specific PATH, e.g.

ssh user@example.com command

will not have ~/.local/bin included, because only ~/.bashrc is used for such a case!

How CentOS 8 does it (“work in progress”)

CentOS/RHEL 8 had a history of changes in the way custom user PATH was included to either ~/.bashrc or ~/.bash_profile.

It was present in 8.0 in ~/.bash_profile, then in ~/.bashrc in subsequent versions. Seems that this is the very part where developers didn’t make up their mind.
At one point between those changes, double-sourcing PATHs was possible, which means that subshells would see this PATH:

/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/home/foo/.local/bin:/home/foo/bin/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/home/foo/.local/bin:/home/foo/bin

Or even lengthier, depending on the nesting.

The latest versions of CentOS/RHEL 8 almost got it right, except that command over ssh still do not source ~/.bash_profile, and source ~/.bashrc instead, for whatever reason.
So it gets “work in progress” label from me.

What you see is what you got

Worth noting that how your specific ~/.bashrc or ~/.bash_profile looks now depends on the way skeleton files were at the time your user was created.
You can find the skeleton files, in e.g. /etc/skel/.bash_profile.

The solution-workaround

In most situations, we:

So the solution is non-intuitive and non-standard and follows up pretty much with the latest RHEL 8 thinking. Set your custom path in ~/.bashrc only

# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]; then
    PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH

The condition prevents double-sourcing, even though we use the non-canonical ~/.bashrc location for our PATH customization.

In this way, finally, things at least will work the right way and as expected.

Exit mobile version