Bash – Handling Duplicate Program Names

bashbashrcexecutablejavapath

I'm wondering if $PATH cascades entries. You'll all need to take a leap of faith with me here, but here it goes.

Let's say we have a Java executable at /usr/bin/java but this version is very old and outdated. Unfortunately, we don't have su access so we can't just replace it. We can, however, download the current version of the JRE/JDK locally and point to the updated version. My question is, how does bash handle the case where we have two or more executables with the same name but in two or more different locations? Does bash somehow choose which one to execute when we type java into the console? Assuming /usr/bin has many other executables that we need, how would the $PATH look for something like this to work correctly?

Ideally, when we type java -version we should see:

java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

instead of

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) Client VM(build 24.45-b08, mixed mode, sharing)

I'm sure this question has been asked before and has some type of jargon associated with it. I've poked around SE, SO, and some forums but didn't find anything conclusive.

Best Answer

Your $PATH is searched sequentially. For example if echo $PATH shows /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin, each of those directories is searched in sequence for a given command (assuming the command isn't an alias or a shell builtin).

If you want to override specific binaries on a per-user basis (or you just don't have access to override for other users than yourself), I would recommend creating a bin directory in your home directory, and then prefixing your PATH variable with that directory.

Like so:

$ cd ~
$ pwd
/home/joe
$ mkdir bin
$ echo "$PATH"
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
$ echo 'export PATH="$HOME/bin:$PATH"' >> .bash_profile

Then source .bash_profile so the new PATH definition will take effect (or just log out and log in, or restart your terminal emulator).

$ source .bash_profile
$ echo "$PATH"
/home/joe/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin

Now, any executable files you put in /home/joe/bin/ will take precedence over system binaries and executables.


Note that if you do have system access and the overrides should apply to all users, the preferred place to put override executables is /usr/local/bin, which is intended for this purpose. In fact often /usr/local/bin is already the first directory in $PATH specifically to allow this.

Related Question