My PATH variable used to be a mess. I have used UNIX-like systems for 10 years and have carried around my configuration files in one form or another since then.
Think about Solaris, think about /opt (or /sw), and change the order based on different requirements.
I have seen a lot of people devise clever if-then-else logic with OS-detection. I have seen yet other, myself included, who tried to aim for the most comprehensive and all-inclusive PATH.
In the end, all that matters is that when you type a command, it IS in your path
As for MANPATH, the situation was even worse. I used to depend (and hope) that the OS-inherited MANPATH contained everything I needed. For a long time, I didn’t bother to set it right and just googled for the man pages if/when I was in need.
Invoking man for something I just installed often meant getting no help at all.
Where to look?
When it comes to bin and share/man directories, there are a handful of predictable places to look for. For PATH:
Notice the bin and sbin combinations. And for MANPATH:
It should be clear that there is a lot of duplication there. Also, if you change the order of your PATH, you should probably change the order of your MANPATH so that the command you get the man page for is the command invoked by your shell. The GNU man pages are not very useful when you are using the BSD commands, on Darwin, for example.
Here’s the plan:
- Clear both PATH and MANPATH.
- Given a path, detect the presence of a bin, sbin and share/man subdirectories.
- Prepend the existing directories from step 2 to both PATH and MANPATH (as appropriate).
What you get:
- Only existing paths go in PATH and MANPATH. No more just-in-case™ and for-some-other-OS™ paths polluting your variables.
- Order of the paths is the same for both PATH and MANPATH. If you change the order in one, the order is changed for the other.
- Easier to read configuration files. Colon-separated lists are no fun to parse visually.
Here’s something you can put in your .bashrc
# prepend_colon(val, var)
if [ -z "$2" ]; then
if [ -d $1/sbin ]; then
export PATH=$(prepend_colon "$1/sbin" $PATH)
if [ -d $1/bin ]; then
export PATH=$(prepend_colon "$1/bin" $PATH)
if [ -d $1/share/man ]; then
export MANPATH=$(prepend_colon "$1/share/man" $MANPATH)
# TABULA RASA
export PATH=$(prepend_colon ".local" $PATH)
I use $HOME/local to store machine-specific binaries/scripts. For example, that’s where I install homebrew on Mac OS X. That’s also where I would put cron scripts or other “I just use this script on this machine” type of things.
I use $HOME/etc to store binaries I carry around with my configuration files. That’s where I clone my dotfiles project.
Finally, the relative path .local is an interesting hack. It allows for directory-specific binaries. This solves the “I just use this script when I’m in that directory” problem. This trick is discussed in this blog post.