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-alternatives solves
  • 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/python2 or /usr/bin/python3.
  • Alternative name: The group name that alternatives belong to, like python in our example.
  • Alternative link: The master symlink path that points to the highest priority alternative, /usr/local/bin/python for 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 link
  • python: Alternative group name
  • /usr/bin/python2: Path to command for this alternative
  • 1: Priority of this alternative, lower means lower precedence

Let‘s breakdown what we did:

  1. Created a new alternative group called python
  2. Added /usr/bin/python2 as an option with priority 1
  3. Added /usr/bin/python3 as an option with priority 2

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.

Similar Posts