Computer Science / Linux / Mac / Tutorials

An Introduction to Linux/Unix Executables, $PATH, Aliases, and Symlinks

This article is intended for those who want to shed a little bit more light on the file and directory structure of their MacOS X or Linux operating system.

Writing this article was a very exciting process, since it took me some time of exploration and experimentation until I understood the underlying concept. Hopefully, I can enthuse you too and give you a good explanation of how paths, aliases and symlinks work.

Linux & Unix file structure and the ‘/bin’ directory

At the very top of the file system is the so-called “Root” directory, symbolized by a slash (“/”).
Although Root contains a variety of different subdirectories, we want to focus on those that contain executable files, the so-called “binaries.”

Mac_root

The “/bin” directory (short for “binaries”) contains the main programs the system needs to operate, including the shells you are using. There is another subfolder in root, called "/sbin" that also contains important programs, which are required for essential administrative processes.
To make it a little bit more convoluted: Those directories mentioned above are not the only ones that contain programs. There are also (at least) “/usr/bin”, “usr/sbin”, “usr/local/bin” and “usr/local/sbin.”

Unix_binaries

However, those are not the only directories that contain programs. There are also subdirectories “/usr/bin” and “usr/sbin” that contain programs, both available to all users too.
So what is the difference between “/bin” and “/usr/bin?” Generally, “/bin” contains the most important and essential programs. They can be accessed and executed by all users, including the system’s administrator (same applies to “/sbin”). However, most of the programs you are using might be found under “/usr/bin”, since this the main directory for executable commands, but those are not essential in contrast to “/bin.”

All those directories mentioned above contain executable commands (or programs) that are part of the distribution where the local directories, “usr/local/bin” and “usr/local/sbin,” contain programs that were installed by the “local” user – basically, those are binaries that are not part of the distribution, but were installed additionally.

Example: Python 3.3 Executable

Let’s take “Python 3.3” for example. So, I downloaded the Python 3.3.0 Mac OS X 64-bit/32-bit x86-64/i386 Installer from Python.org and used the default options to install it. Now, when I open up my terminal, go to any location, and type “python3”: it just works! But where are the binaries located that are executed by this “python3” command? Just enter the following command into the terminal to find out:

which python3

On my machine the result is:

/usr/local/bin/python3

However, as I will describe it later in more detail, this is not the “real” executable, but just a pointer, a so-called “symlink” (short for symbolic link). Essentially, a symlink is just a file that only purpose it is to link to another file.
Now, in order to find the “real” executable of Python 3.3, you can do the following: Launch Python in the terminal and type:

import sys 
sys.prefix

This will return a string that tells you where the Python files are installed.
In my case it returns

/Library/Frameworks/Python.framework/Versions/3.3

and in this folder I find the executable

/Library/Frameworks/Python.framework/Versions/3.3/bin/python3

So, as it turns out, the Python installer created a symlink,

/usr/local/bin/python3

that points to the executable at

/Library/Frameworks/Python.framework/Versions/3.3/bin/python3

when I enter “python3” in my shell to open this program.

Why this symlink is necessary to run Python 3.3 by typing “python3” will become clear in the next section about “$PATH.”

$PATH

As the Dollar symbol indicates, $PATH is variable. Furthermore, it is a more “powerful” version of a variable, a so-called “environment variable” (indicated by the common convention to use upper case letters for environment variables). In contrast to shell variables, environment variables are set at login and are valid even if you open up a new shell window.
Now, let’s come to the interesting part.
The values that are stored in $PATH are the absolute paths to the locations where the system will search for executables if you enter a command.
E.g., if you enter “python3” into your shell window, the system will look in all paths saved under $PATH for the executable “python3.”
To check what those paths are, you can type the following command into the terminal:

echo $PATH

On my machine, those paths are

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

(Note that the individual paths are separated by colons).

So for the Python 3.3 example I described in the “Python 3.3 Executable” section above, the following will happen if I enter “python3” into my shell:
The system searches the paths stored under $PATH for an exectuable called “python3”
it finds "/usr/local/bin/python3"
however, "/usr/local/bin/python3" is just a symlink, which in turn points to "/Library/Frameworks/Python.framework/Versions/3.3/bin/python3."

"/Library/Frameworks/Python.framework/Versions/3.3/bin/python3" eventually is the executable that runs Python 3.3

Three Ways To Call Executable Programs

Ignore that the symlink "/usr/local/bin/python3" was created automatically during the python installation for a moment – or just assume that I deleted this symlink manually.
In this case, and if the Python 3.3 executable resides in

/Library/Frameworks/Python.framework/Versions/3.3/bin/python3

you would have to type the same line (the absolute path to the executable)
"/Library/Frameworks/Python.framework/Versions/3.3/bin/python3"
into the shell to run Python 3.3.

Now, there are 3 ways to achieve that Python starts by just typing the “python3” command.

1) Add the absolute path of the executable to $PATH

# PYTHON PATHs 
export PATH=/Library/Frameworks/Python.framework/Versions/3.3/bin:${PATH}

What this line basically does, is, that it adds the absolute path, where the “python3” executable is located, to the beginning of the existing $PATH variable. Why adding it to the beginning and not to the end? Well, this is a common convention, since the system looks for the executable in the paths under $PATH in the very order they are given. If your $PATH looks like this

/Library/Frameworks/Python.framework/Versions/3.3/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

The first location to be searched will be "/Library/Frameworks/Python.framework/Versions/3.3/bin." This is expecially handy if you have multiple executables with the same name.

But be aware, some users reported that a very large $PATH slowed down there shells (see the discussion I started under: http://stackoverflow.com/questions/14917942/advantage-of-path-over-alias#comment20942357_14917942)

Note: to make this modification work permanently, add this line to your .bashrc, .bash_profile, .cshrc, or .csh_profile file (see the section “excursus to .bashrc and .bash_profile” below)

2) Create an alias to the executable
alias python3=/Library/Frameworks/Python.framework/Versions/3.3/bin/python3

With this method, you simply create an alias (or shortcut) “python3” that points to the absolute path of the Python 3.3 executable when you type “python3.”

Note: to make this modification work permanently, add this line to your .bashrc, .bash_profile, .cshrc, or .csh_profile file (see “excursus to .bashrc and .bash_profile” below)

3) Create a symlink to the executable

sudo ln -s /Library/Frameworks/Python.framework/Versions/3.3/bin/python3 /usr/local/bin/python3

Just as the default installer did, this command creates a symlink that points to the Python 3.3 executable and puts it intoone of the directories listed under $PATH, here: "/usr/local/bin/."

The advantage of this method over aliases is that it works for all users, independent from their shell configuration file.

Excursus to .bashrc and .bash_profile

There is a variety of different shells available for Unix and Linux, such as the popular Bash-shell (Bourne Again SHell), Korn shell, C shell, or Tc shell. To find out which shell you are currently using, type

echo $SHELL

into the command line.

Each shell has its own configuration file that sits in your home directory. Basically, this is just a shell script that is executed when you open up a new shell window. E.g., if you are using a Bash-shell, this file is called “.bashrc” (the period in front of the file makes it invisible by default, so you have to enter “ls -a” to see it in your home directory).
You may notice another file in your home directory called “.bash_profile”, which does a very similar thing like “.bashrc.” The difference is that “.bash_profile” is only executed if you login into a shell, and “.bashrc” is executed if you open up a new interactive non-login shell – so basically each time you open a new shell window.

So, if you login into a shell session, firstly commands from "/etc/profile" are executed (this file contains shell configuration files for all users), and secondly "/home/.bash_profile" is read. If such a file doesn’t exist, the system will try to read from /home/.profile.
And if you open a new interactive shell while you are already logged in, the commands /home/.bashrc are executed.

Since .bashrc only applies to the bash shell, it’s recommended to put paths, aliases etc. into this file. Usually, the .bash_profile file contains a command that invokes .bashrc at login, however, I noticed that this might not necessarily the case in MacOS X. Thus I recommend for Mac users to put aliases etc. directly into .bash_profile.

Let’s say you created a symlink for the Python 3.3 executable, for example:

sudo ln -s /Library/Frameworks/Python.framework/Versions/3.3/bin/python3 /usr/local/bin/python3

Here, you created a physical “link,” and you don’t have to worry about the shell configuration files. But if you created an alias or added the executable-path to $PATH, this will only work for your current shell session, meaning if you close the shell, the alias is gone and the $PATH modification is set back to default, respectively.
To have this $PATH modification, or alias available each time you log in into a new shell, simply put them into .bashrc or .bash_profile as described above.

Note that the syntax for C- and TC-shells is slightly different:

setenv PATH ”/Library/Frameworks/Python.framework/Versions/3.3/bin:${PATH}”
alias python3 /Library/Frameworks/Python.framework/Versions/3.3/bin/python3

Conclusion

To summarize the main points of this article: executables are usually located in some “bin” directory. However, sometimes binaries are located somewhere else, and there are (at least) three ways to create pointers to this directory: symlinks, aliases, and modifications of the $PATH variable.

After writing this article, I can honestly say that this is my favorite one so far. It was a lot of fun to explore my MacOS X a little bit further and try some things out. If you read it to the end, I hope I could provide you with some insights, too, and furthermore could enthuse you to do some explorations by yourself.
In case you notice something that does not really make sense to you, or if I got some things wrong, I would be happy about your comments!

About these ads

2 thoughts on “An Introduction to Linux/Unix Executables, $PATH, Aliases, and Symlinks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s