How To

update-alternatives on Ubuntu: Manage Default Program Links

When two or more installed programs provide the same command name, the system needs a way to decide which one runs by default.

The update-alternatives command on Ubuntu, Debian, and their derivatives manages this through symbolic links in /etc/alternatives. This guide covers how to inspect alternative groups, switch between programs interactively or from a script, register custom paths, and return a group to automatic mode.

How update-alternatives Works on Ubuntu and Debian

update-alternatives maintains link groups. Each group has a generic command name and one or more registered program paths. The java group, for example, controls which installed JVM /usr/bin/java starts.

The link structure is indirect by design. /usr/bin/java points to /etc/alternatives/java, which points to the active binary. Changing the alternative updates only the link in /etc/alternatives — any script or tool calling /usr/bin/java picks up the new selection without modification. Administrative state is stored in /var/lib/dpkg/alternatives.

Each group runs in one of two modes. Automatic mode selects the registered path with the highest priority. Package installs can update the active choice when they register a higher-priority entry. Manual mode preserves the administrator’s selection until it is explicitly changed or the path is removed. Package installs can add new choices but will not override the current selection.

List every registered group with its mode and active path:

bashupdate-alternatives --get-selections

List registered paths for one group:

bashupdate-alternatives --list java

See full details with priorities and slave links:

bashupdate-alternatives --display java

Slave links are related files that follow the same group selection. For java, the man page (java.1.gz) automatically switches to match the active JVM version. Groups are independent — switching java does not switch javac.

Switch, Set, and Register Alternatives

Switch interactively with --config. The command shows a numbered menu of all registered paths:

bashsudo update-alternatives --config java

Type a selection number and press Enter. Choosing 0 restores automatic mode. Any numbered choice moves the group to manual mode.

Switch without a menu using --set. Copy the exact path from --list and pass it directly. This is the right approach for provisioning scripts because it requires no user input:

bashsudo update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java

Register a custom alternative with --install for programs installed outside the package manager. The four arguments are: the symlink path, the group name, the real binary path, and the priority number:

bashsudo update-alternatives --install /usr/local/bin/acme-tool acme-tool /opt/acme-tool-1.0/bin/acme-tool 100sudo update-alternatives --install /usr/local/bin/acme-tool acme-tool /opt/acme-tool-2.0/bin/acme-tool 200

In auto mode, version 2.0 wins because 200 > 100. Both paths must exist on disk before registration.

Do not replace /usr/bin/python3 using update-alternatives on Ubuntu or Debian. System tools including apt depend on the distribution’s exact Python version. Use pyenv, a virtual environment, or a separate command name under /usr/local/bin instead.

Remove Alternatives, Reset to Auto, and Troubleshooting

Deregister a specific path with --remove. The entry is removed from the database but the binary is not deleted:

bashsudo update-alternatives --remove acme-tool /opt/acme-tool-1.0/bin/acme-tool

If the removed path was the active selection, the group returns to auto mode and selects the best remaining entry.

Restore automatic mode at any time with --auto:

bashsudo update-alternatives --auto java

Common errors and fixes:

  • no alternatives for NAME — the group is not registered. Check existing groups with update-alternatives --get-selections, then install a package that provides the group or register an existing binary with --install
  • alternative path ... does not exist — the binary must exist on disk before registration. Verify with ls -l PATH
  • A regular file blocks the alternatives link — do not add --force without checking first. Run dpkg -S /path/to/command to see which package owns the file, and back up any locally installed binary before replacing it

Use --config for interactive changes, --set for scripts, and --auto to restore priority-based selection. Leave a comment below if you run into any issues.

Cyber Defence

Recent Posts

Install Docker on Ubuntu 26.04: Official Repository Setup Guide

Install Docker on Ubuntu 26.04: Official Repository Setup GuideDocker is an open-source container platform that…

2 days ago

Install Asterisk on Ubuntu 18.04: Source Build and Secure Config

Asterisk is the most widely deployed open-source PBX (Private Branch Exchange) platform in the world. It…

3 days ago

Install Ghost on Ubuntu 18.04: Node.js, MySQL, and Nginx SSL

Ghost is an open-source publishing platform built on Node.js. It is designed for bloggers, journalists, and…

3 days ago

Install Mattermost on Ubuntu 18.04: Nginx SSL Reverse Proxy Setup

Mattermost is an open-source, self-hosted team messaging platform and a direct alternative to Slack. It is…

3 days ago

Install Ruby on Ubuntu 18.04: apt, Rbenv, and RVM Methods

Ruby is a dynamic, open-source programming language known for its clean, readable syntax. It powers the…

3 days ago

Install PyCharm on Ubuntu 18.04: Community Edition via Snap

PyCharm is a full-featured Python IDE developed by JetBrains. It includes built-in debugging, embedded Git control,…

3 days ago