As a Linux system administrator, you‘ll often find yourself needing to manage multiple versions of the same command or program. For example, having both Python 2 and Python 3 installed, or multiple PHP versions.
Manually changing symlinks and PATH variables to switch between these tools can be tedious and error-prone. Fortunately, Ubuntu includes a useful utility called update-alternatives that makes command version switching trivial.
In this comprehensive guide, you‘ll learn:
- What problem
update-alternativessolves - How alternatives groups and priorities work
- Installing and switching between alternative commands
- Removing and restoring alternatives
- Advanced use cases for alternatives
So if you need an efficient way to manage and toggle between command versions on Ubuntu, keep reading!
The Problem: Managing Multiple Command Versions
Consider a common scenario – you have Python 2 installed at /usr/bin/python2 and Python 3 installed at /usr/bin/python3.
To run Python 2 code you‘d use:
python2 script.py
And for Python 3:
python3 script.py
This quickly becomes tedious, especially if you switch between Python versions often.
You can create a symlink from /usr/local/bin/python to either python2 or python3, then call that directly. But now switching Python versions means manually updating the symlink target each time.
As you install more software that installs commands to different locations, your PATH variable starts getting polluted as well trying to manage precedence of these tools.
Updating environment variables and symlinks is cumbersome, but thankfully update-alternatives provides an elegant solution for precisely this problem!
Introducing update-alternatives
The update-alternatives system manages groups of command alternatives and links the highest priority one to a "master" path.
For our Python example, we can set up python as the master alternative path, with python2 and python3 as options in its group.
update-alternatives will then symbolically link /usr/bin/python (the master path) to point to either python2 or python3, depending on which has highest priority. If priorities change, it updates the symbolic link automatically.
This allows switching between command versions by simply changing their priority, rather than manually moving symlinks around!
Next let‘s go over some key concepts in update-alternatives, then I‘ll demonstrate practical examples.
Understanding Alternatives Terminology
Here are some common terms used with update-alternatives that are helpful to know:
- Alternative: A specific version of a command, such as
/usr/bin/python2or/usr/bin/python3. - Alternative name: The group name that alternatives belong to, like
pythonin our example. - Alternative link: The master symlink path that points to the highest priority alternative,
/usr/local/bin/pythonfor example. - Priority: Each alternative has a numeric priority. Higher priority alternatives will be linked as the default target.
- Auto mode: Automatically links highest priority alternative. This is the default.
- Manual mode: You explicitly choose the default alternative version.
Now that we‘ve covered the key concepts, let‘s move on to practical examples of managing alternatives!
Installing Alternatives
I‘ll demonstrate on a fresh Ubuntu 18.04 install, but managing alternatives works similarly on any Debian-based distro.
Let‘s install Python 2 and Python 3:
sudo apt install python python3
And verify they are in the expected locations:
which python2
/usr/bin/python2
which python3
/usr/bin/python3
Now we‘ll add these as alternatives under a new group called python:
sudo update-alternatives --install /usr/local/bin/python python /usr/bin/python2 1
sudo update-alternatives --install /usr/local/bin/python python /usr/bin/python3 2
Here‘s an explanation of each part:
update-alternatives: The command for managing alternatives--install: Adds a new alternative/usr/local/bin/python: Path for the master alternative linkpython: Alternative group name/usr/bin/python2: Path to command for this alternative1: Priority of this alternative, lower means lower precedence
Let‘s breakdown what we did:
- Created a new alternative group called
python - Added
/usr/bin/python2as an option with priority1 - Added
/usr/bin/python3as an option with priority2
Since python3 has highest priority, the /usr/local/bin/python symlink now points to /usr/bin/python3.
Let‘s verify this:
update-alternatives --display python
python - auto mode
link best version is /usr/bin/python3
link currently points to /usr/bin/python3
link python is /usr/local/bin/python
slave python.1.gz is /usr/share/man/man1/python.1.gz
/usr/bin/python2 - priority 1
/usr/bin/python3 - priority 2
We can see python3 is indeed configured as the current best alternative. And the master link at /usr/local/bin/python points to it.
So now if we run python --version we should see Python 3 output:
python --version
Python 3.6.5
Success! We‘ve now got an automated way to switch between Python versions. Next let‘s see how to actually change between alternatives.
Switching Alternatives
One benefit of the alternatives system is you can flexibly move your master link between options. Let‘s switch from Python 3 back to Python 2.
First, check what alternatives are currently available in the python group:
update-alternatives --query python
Name: python
Link: /usr/local/bin/python
Slaves:
python.1.gz /usr/share/man/man1/python.1.gz
Status: auto
Best: /usr/bin/python3
Value: /usr/bin/python3
Alternative: /usr/bin/python2
Priority: 1
Slaves:
Alternative: /usr/bin/python3
Priority: 2
Slaves:
We can see python3 is currently configured as the best alternative. To change to python2, run:
sudo update-alternatives --config python
There are 2 choices for the alternative python (providing /usr/local/bin/python).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/python3 2 auto mode
1 /usr/bin/python2 1 manual mode
2 /usr/bin/python3 2 manual mode
Press <enter> to keep the current choice[*], or type selection number: 1
We selected python2, so now our master python link points to it:
update-alternatives –query python
Name: python
Link: /usr/local/bin/python
Status: manual
Best: /usr/bin/python3
Value: /usr/bin/python2
Alternative: /usr/bin/python2
Priority: 1
Slaves:
Alternative: /usr/bin/python3
Priority: 2
Slaves:
Now running `python --version` confirms we‘re on Python 2:
python –version
Python 2.7.15rc1
So in just a few commands we flipped the default python symlink to point to Python 2 instead!
The `--config` option is handy any time you need to manually switch the active alternative.
Next let‘s look at how to remove an alternative from the group.
## Removing an Alternative
Over time you‘ll upgrade or replace software with newer versions. As you decommission old command versions, you‘ll want to prune their alternative definitions too.
Let‘s remove our Python 2 alternative:
sudo update-alternatives –remove python /usr/bin/python2
Now only python3 remains:
update-alternatives –query python
Name: python
Link: /usr/local/bin/python
Status: auto
Best: /usr/bin/python3
Value: /usr/bin/python3
Alternative: /usr/bin/python3
Priority: 2
Slaves:
Easy as that!
If you ever want to completely remove an alternatives group, there‘s also:
sudo update-alternatives –remove-all python
This erases the group definition entirely. Useful for cleaning up old or unused alternatives.
Up next we‘ll cover resetting alternatives when things go wrong.
## Resetting Alternatives
Sometimes you may break an alternatives group, for example pointing the symlink incorrectly to a non-existent path.
Thankfully `update-alternatives` makes it easy to reset everything to a clean state.
Let‘s demonstrate by forcing the python group into an error state:
sudo rm /usr/local/bin/python # Delete symlink
sudo update-alternatives –auto python
update-alternatives: error: alternative path /usr/local/bin/python doesn‘t exist
Now the python alternative group is broken - the master link path is missing.
To fix this, simply use `--auto` again to recreate the symlink:
sudo update-alternatives –auto python
update-alternatives: using /usr/bin/python3 to provide /usr/local/bin/python (python) in auto mode
The master path gets rebuilt correctly pointing to python3, our highest priority alternative.
So if your alternatives group ever gets corrupted, `--auto` makes it easy to get back into a good state.
Now let‘s move on to some advanced use cases and tricks for alternatives.
## Advanced Alternative Uses
While switching command versions is the most common use case, the alternatives system is extremely flexible. You can manage symlinks for all kinds of files not just scripts.
Here are some more advanced examples of leveraging alternatives:
### Alternative slave links
We touched on this briefly earlier, but alternatives can have slave symlinks tied to the master path.
For python there is a slave manpage link at `/usr/share/man/man1/python.1.gz`. Whenever the main python command alternative changes, this symlink updates too.
This keeps manpages in sync across software versions changes.
To add your own slave links:
sudo update-alternatives –install /path/to/master link /path/to/alternative 1 \
–slave /path/to/slave slave_link
Just append the `--slave` option pointing your slave name and symlink path.
### Choosing by pattern match
When running `update-alternatives --config`, you choose alternatives via their menu number. But did you know you can also pick by regex pattern matching on the path?
This is handy for alternatives with many options, or if menu numbers change over time.
For example, choosing Python 2 explicitly by path pattern:
sudo update-alternatives –config python
There are 2 choices for the alternative python…
Selection Path
- 0 /usr/bin/python3
1 /usr/bin/python2
Enter to keep the current choice[+], or type selection pattern: ^python2$
This selects the second option by matching "python2" at the end of its path string.
### Option priority weighting
Each alternative has a priority value you define during `--install`. But did you know priorities can go higher than just using sequential numbers?
By using larger priority gaps between options, you can create a weighted preference.
For example:
update-alternatives –install /path python /path/to/python3 100
update-alternatives –install /path python /path/to/python2 10
Now python3 has a much higher change of being selected as best alternative. But python2 remains available as a fallback if removed.
### Tab complete alternative values
Once you create an alternatives group, you can tab complete alternative values on the CLI!
Consider this group with multiple editor options:
$ update-alternatives –display editor
editor – status is auto
link currently points to /usr/bin/vim
slave editor.1.gz /usr/share/man/man1/vim.1.gz
slave editor.fr.1.gz /usr/share/man/fr/man1/vim.1.gz
/usr/bin/nano – priority 10
slave editor.1.nanoz.gz /usr/share/man/es.UTF-8/man1/nano.1.gz
/usr/bin/vim – priority 30
$ update-alternatives –set editor
–set editor /usr/bin/nano /usr/bin/vim
This makes it easy to select valid values at the command line.
## Wrap Up
That wraps up this guide on managing command alternatives on Ubuntu. We covered a lot of ground!
- The problem space of juggling multiple command versions
- How `update-alternatives` solves that problem with flexible symlinks
- Key concepts like alternatives, priority, slave links
- Practical examples for adding, configuring, and removing alternatives
- Advanced use cases like tab completion and priority weighting
Now you have a complete professional-level understanding of updating alternatives on Ubuntu!
You should feel comfortable installing alternative groups, switching between options, and fixing issues with links.
Using `update-alternatives` prevents piles of manual symlinks to manage installations. Making it easy to keep multiple command versions on your system.
So next time you go to install that hot new software beta - don‘t dread having to juggle more PATH variables! Just throw it in an alternatives group and call it a day.


