my cheat sheet on linux alternatives

1 /etc/alternatives

The alternatives command started from the Debian update-alternatives command. It is a slightly more sophisticated way of maintaining symlinks to multiple versions of a command, like python3 or gcc.

Normally the actual program files reside in the usual places such as

  • /usr/local/bin or even
  • /usr/bin

From the man page:

alternatives creates, removes, maintains and displays information about the symbolic links comprising the alternatives system.

It is possible for several programs fulfilling the same or similar functions to be installed on a single system at the same time. For example, many systems have several text editors installed at once. This gives choice to the users of a system, allowing each to use a different editor, if desired, but makes it difficult for a program to make a good choice of editor to invoke if the user has not specified a particular preference.

The alternatives system aims to solve this problem. A generic name in the filesystem is shared by all files providing interchangeable functionality. The alternatives system and the system administrator together determine which actual file is referenced by this generic name. For example, if the text editors ed(1) and nvi(1) are both installed on the system, the alternatives system will cause the generic name /usr/bin/editor to refer to /usr/bin/nvi by default. The system administrator can override this and cause it to refer to /usr/bin/ed instead, and the alternatives system will not alter this setting until explicitly requested to do so.

The generic name is not a direct symbolic link to the selected alternative. Instead, it is a symbolic link to a name in the alternatives directory, which in turn is a symbolic link to the actual file referenced. This is done so that the system administrator's changes can be confined within the /etc directory: the FHS (q.v.) gives reasons why this is a Good Thing.

When each package providing a file with a particular functionality is installed, changed or removed, alternatives is called to update information about that file in the alternatives system. alternatives is usually called from the %post or %pre scripts in RPM packages.

1.0.1 alternatives linking:

Continuing from the man page:

It is often useful for a number of alternatives to be synchronised, so that they are changed as a group; for example, when several versions of the vi(1) editor are installed, the man page referenced by /usr/share/man/man1/vi.1 should correspond to the executable referenced by /usr/bin/vi.

alternatives handles this by means of master and slave links; when the master is changed, any associated slaves are changed too. A master link and its associated slaves make up a link group.

Each link group is, at any given time, in one of two modes: automatic or manual. When a group is in automatic mode, the alternatives system will automatically decide, as packages are installed and removed, whether and how to update the links. In manual mode, the alternatives system will not change the links; it will leave all the decisions to the system administrator.

Link groups are in automatic mode when they are first introduced to the system. If the system administrator makes changes to the system's automatic settings, this will be noticed the next time alternatives is run on the changed link's group, and the group will automatically be switched to manual mode.

Each alternative has a priority associated with it. When a link group is in automatic mode, the alternatives pointed to by members of the group will be those which have the highest priority.

When using the –config option, alternatives will list all of the choices for the link group of which given name is the master link. You will then be prompted for which of the choices to use for the link group. Once you make a change, the link group will no longer be in auto mode. You will need to use the –auto option in order to return to the automatic state. #+ENDEXAMPLE

1.1 Examples /etc/alternatives

zintis@acme.org /etc/alternatives[1013]:
$ ls -l
total 108
lrwxrwxrwx 75 May 25 14:16 alt-java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/alt-java
lrwxrwxrwx 79 May 25 14:16 alt-java.1.gz -> /usr/share/man/man1/alt-java-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 39 Mar  9  2021 cifs-idmap-plugin -> /usr/lib64/cifs-utils/cifs_idmap_sss.so
lrwxrwxrwx 25 May 31  2021 easy_install-3 -> /usr/bin/easy_install-3.6
lrwxrwxrwx 19 May 25 14:16 emacs -> /usr/bin/emacs-26.1
lrwxrwxrwx 20 May 25 14:15 emacs.etags -> /usr/bin/etags.emacs
lrwxrwxrwx 36 May 25 14:15 emacs.etags.man -> /usr/share/man/man1/etags.emacs.1.gz
lrwxrwxrwx 22 Mar  9  2021 ifdown -> /usr/libexec/nm-ifdown
lrwxrwxrwx 20 Mar  9  2021 ifup -> /usr/libexec/nm-ifup
lrwxrwxrwx 71 May 25 14:16 java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/java
lrwxrwxrwx 75 May 25 14:16 java.1.gz -> /usr/share/man/man1/java-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 70 May 25 14:16 jjs -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/jjs
lrwxrwxrwx 74 May 25 14:16 jjs.1.gz -> /usr/share/man/man1/jjs-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 62 May 25 14:16 jre -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre
lrwxrwxrwx 62 May 25 14:16 jre_1.8.0 -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre
lrwxrwxrwx 57 May 25 14:16 jre_1.8.0_openjdk -> /usr/lib/jvm/jre-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64
lrwxrwxrwx 62 May 25 14:16 jre_openjdk -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre
lrwxrwxrwx 74 May 25 14:16 keytool -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/keytool
lrwxrwxrwx 78 May 25 14:16 keytool.1.gz -> /usr/share/man/man1/keytool-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 15 Apr 15  2021 ld -> /usr/bin/ld.bfd
lrwxrwxrwx 34 Mar  9  2021 libnssckbi.so.x86_64 -> /usr/lib64/pkcs11/p11-kit-trust.so
lrwxrwxrwx 33 May 25 14:24 module.1.gz -> /usr/share/man/man1/module-c.1.gz
lrwxrwxrwx 40 May 25 14:24 modulecmd -> /usr/share/Modules/libexec/modulecmd.tcl
lrwxrwxrwx 37 May 25 14:24 modulefile.4.gz -> /usr/share/man/man4/modulefile-c.4.gz
lrwxrwxrwx 35 May 25 14:24 modules.csh -> /usr/share/Modules/init/profile.csh
lrwxrwxrwx 34 May 25 14:24 modules.sh -> /usr/share/Modules/init/profile.sh
lrwxrwxrwx 71 May 25 14:16 orbd -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/orbd
lrwxrwxrwx 75 May 25 14:16 orbd.1.gz -> /usr/share/man/man1/orbd-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 74 May 25 14:16 pack200 -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/pack200
lrwxrwxrwx 78 May 25 14:16 pack200.1.gz -> /usr/share/man/man1/pack200-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 16 May 31  2021 pip-3 -> /usr/bin/pip-3.6
lrwxrwxrwx 15 May 31  2021 pip3 -> /usr/bin/pip3.6
lrwxrwxrwx 77 May 25 14:16 policytool -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/policytool
lrwxrwxrwx 81 May 25 14:16 policytool.1.gz -> /usr/share/man/man1/policytool-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 17 May 31  2021 pydoc-3 -> /usr/bin/pydoc3.6
lrwxrwxrwx 17 May 31  2021 pydoc3 -> /usr/bin/pydoc3.6
lrwxrwxrwx 22 Mar  9  2021 python -> /usr/libexec/no-python
lrwxrwxrwx 18 May 31  2021 python3 -> /usr/bin/python3.6
lrwxrwxrwx 34 May 31  2021 python3-man -> /usr/share/man/man1/python3.6.1.gz
lrwxrwxrwx 19 May 31  2021 pyvenv-3 -> /usr/bin/pyvenv-3.6
lrwxrwxrwx 71 May 25 14:16 rmid -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/rmid
lrwxrwxrwx 75 May 25 14:16 rmid.1.gz -> /usr/share/man/man1/rmid-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 78 May 25 14:16 rmiregistry -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/rmiregistry
lrwxrwxrwx 82 May 25 14:16 rmiregistry.1.gz -> /usr/share/man/man1/rmiregistry-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 77 May 25 14:16 servertool -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/servertool
lrwxrwxrwx 81 May 25 14:16 servertool.1.gz -> /usr/share/man/man1/servertool-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 76 May 25 14:16 tnameserv -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/tnameserv
lrwxrwxrwx 80 May 25 14:16 tnameserv.1.gz -> /usr/share/man/man1/tnameserv-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 76 May 25 14:16 unpack200 -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/unpack200
lrwxrwxrwx 80 May 25 14:16 unpack200.1.gz -> /usr/share/man/man1/unpack200-java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64.1.gz
lrwxrwxrwx 43 Mar  9  2021 unversioned-python-man -> /usr/share/man/man1/unversioned-python.1.gz
lrwxrwxrwx 17 Aug 29  2021 whois -> /usr/bin/whois.md
lrwxrwxrwx 33 Aug 29  2021 whois-man -> /usr/share/man/man1/whois.md.1.gz
zintis@acme.org /etc/alternatives[1014]:

1.2 alternatives –list

$ alternatives --list
cifs-idmap-plugin       auto    /usr/lib64/cifs-utils/cifs_idmap_sss.so
libnssckbi.so.x86_64    auto    /usr/lib64/pkcs11/p11-kit-trust.so
python3                 auto    /usr/bin/python3.6
jre_1.8.0_openjdk       auto    /usr/lib/jvm/jre-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64
jre_openjdk             auto    /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre
java                    auto    /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre/bin/java
ifup                    auto    /usr/libexec/nm-ifup
modules.sh              auto    /usr/share/Modules/init/profile.sh
emacs                   auto    /usr/bin/emacs-26.1
python                  auto    /usr/libexec/no-python
emacs.etags             auto    /usr/bin/etags.emacs
ld                      auto    /usr/bin/ld.bfd
whois                   auto    /usr/bin/whois.md
jre_1.8.0               auto    /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.372.b07-4.el8.x86_64/jre

1.3 alternatives –display python3 (before 3.11 install)

Here is my python3 before I installed python3.11:

zintis@acme.org /usr/bin[1007]: alternatives --display python3
python3 - status is auto.
 link currently points to /usr/bin/python3.6
/usr/bin/python3.6 - priority 1000000
 slave easy_install-3: /usr/bin/easy_install-3.6
 slave pip-3: /usr/bin/pip-3.6
 slave pip3: /usr/bin/pip3.6
 slave pydoc-3: /usr/bin/pydoc3.6
 slave pydoc3: /usr/bin/pydoc3.6
 slave pyvenv-3: /usr/bin/pyvenv-3.6
 slave python3-man: /usr/share/man/man1/python3.6.1.gz
/usr/bin/python3.9 - priority 3900
 slave easy_install-3: /usr/bin/easy_install-3.9
 slave pip-3: /usr/bin/pip-3.9
 slave pip3: /usr/bin/pip3.9
 slave pydoc-3: /usr/bin/pydoc3.9
 slave pydoc3: /usr/bin/pydoc3.9
 slave pyvenv-3: (null)
 slave python3-man: /usr/share/man/man1/python3.9.1.gz
Current `best' version is /usr/bin/python3.6.
zintis@acme.org /usr/bin[1008]:
/usr/bin/python priority priority current
file   post install "best"
python3.6 1000000 n/a yes
python3.9 3900 n/a  

1.4 Install python3.11

At this point, I did a straight dnf install of python3.11 using this command:

  • sudo dnf install python3.11

For completeness, here is the output:

sudo dnf install python3.11
Last metadata expiration check: 2:37:36 ago on Sun 28 May 2023 09:09:47 AM EDT.
Dependencies resolved.
=====================================================================================
 Package                        Architecture    Version           Repository    Size
=====================================================================================
Installing:
 python3.11                     x86_64          3.11.2-2.el8      appstream     29 k
Installing dependencies:
 mpdecimal                      x86_64          2.5.1-3.el8       appstream     92 k
 python3.11-libs                x86_64          3.11.2-2.el8      appstream     10 M
 python3.11-pip-wheel           noarch          22.3.1-2.el8      appstream    1.4 M
 python3.11-setuptools-wheel    noarch          65.5.1-2.el8      appstream    719 k
Installing weak dependencies:
 python3.11-tkinter             x86_64          3.11.2-2.el8      appstream    406 k

Transaction Summary
===============================================================
Install  6 Packages

Total download size: 13 M
Installed size: 49 M
Is this ok [y/N]: y
Downloading Packages:
(1/6): mpdecimal-2.5.1-3.el8.x86_64.rpm                            741 kB/s |  92 kB     00:00    
(2/6): python3.11-pip-wheel-22.3.1-2.el8.noarch.rpm                8.8 MB/s | 1.4 MB     00:00    
(3/6): python3.11-setuptools-wheel-65.5.1-2.el8.noarch.rpm         9.9 MB/s | 719 kB     00:00    
(4/6): python3.11-tkinter-3.11.2-2.el8.x86_64.rpm                  7.2 MB/s | 406 kB     00:00    
(5/6): python3.11-libs-3.11.2-2.el8.x86_64.rpm                      19 MB/s |  10 MB     00:00    
(6/6): python3.11-3.11.2-2.el8.x86_64.rpm                           43 kB/s |  29 kB     00:00    
----------------------------------------------------------------
Total                                                               15 MB/s |  13 MB     00:00     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                    1/1 
  Installing       : python3.11-setuptools-wheel-65.5.1-2.el8.noarch                                                                    1/6 
  Installing       : python3.11-pip-wheel-22.3.1-2.el8.noarch                                                                           2/6 
  Installing       : mpdecimal-2.5.1-3.el8.x86_64                                                                                       3/6 
  Installing       : python3.11-tkinter-3.11.2-2.el8.x86_64                                                                             4/6 
  Installing       : python3.11-3.11.2-2.el8.x86_64                                                                                     5/6 
  Running scriptlet: python3.11-3.11.2-2.el8.x86_64                                                                                     5/6 
  Installing       : python3.11-libs-3.11.2-2.el8.x86_64                                                                                6/6 
  Running scriptlet: python3.11-libs-3.11.2-2.el8.x86_64                                                                                6/6 
  Verifying        : mpdecimal-2.5.1-3.el8.x86_64                                                                                       1/6 
  Verifying        : python3.11-3.11.2-2.el8.x86_64                                                                                     2/6 
  Verifying        : python3.11-libs-3.11.2-2.el8.x86_64                                                                                3/6 
  Verifying        : python3.11-pip-wheel-22.3.1-2.el8.noarch                                                                           4/6 
  Verifying        : python3.11-setuptools-wheel-65.5.1-2.el8.noarch                                                                    5/6 
  Verifying        : python3.11-tkinter-3.11.2-2.el8.x86_64                                                                             6/6 

Installed:
  mpdecimal-2.5.1-3.el8.x86_64
  python3.11-3.11.2-2.el8.x86_64
  python3.11-libs-3.11.2-2.el8.x86_64      
  python3.11-pip-wheel-22.3.1-2.el8.noarch
  python3.11-setuptools-wheel-65.5.1-2.el8.noarch
  python3.11-tkinter-3.11.2-2.el8.x86_64   

Complete!
zintis@acme.org /usr/bin[1011]:

Notice that I did NOT touch any alternatives commands. The dnf install post install scripts seemed to take care of it automagically. Nice.

1.5 Post install alternatives –display python:

The very next command I issued was the --dispaly option on the same python3:

$ alternatives --display python3
python3 - status is auto.
 link currently points to /usr/bin/python3.6
/usr/bin/python3.6 - priority 1000000
 slave easy_install-3: /usr/bin/easy_install-3.6
 slave pip-3: /usr/bin/pip-3.6
 slave pip3: /usr/bin/pip3.6
 slave pydoc-3: /usr/bin/pydoc3.6
 slave pydoc3: /usr/bin/pydoc3.6
 slave pyvenv-3: /usr/bin/pyvenv-3.6
 slave python3-man: /usr/share/man/man1/python3.6.1.gz
/usr/bin/python3.9 - priority 3900
 slave easy_install-3: /usr/bin/easy_install-3.9
 slave pip-3: /usr/bin/pip-3.9
 slave pip3: /usr/bin/pip3.9
 slave pydoc-3: /usr/bin/pydoc3.9
 slave pydoc3: /usr/bin/pydoc3.9
 slave pyvenv-3: (null)
 slave python3-man: /usr/share/man/man1/python3.9.1.gz
/usr/bin/python3.11 - priority 31100
 slave easy_install-3: (null)
 slave pip-3: (null)
 slave pip3: (null)
 slave pydoc-3: /usr/bin/pydoc3.11
 slave pydoc3: /usr/bin/pydoc3.11
 slave pyvenv-3: (null)
 slave python3-man: /usr/share/man/man1/python3.11.1.gz
Current `best' version is /usr/bin/python3.6.
$ 
/usr/bin/python priority priority current
file   post install "best"
python3.6 1000000 n/a yes
python3.9 3900 n/a  
python3.11 31100 31100  

After the install of python3.11 /etc/alternatives has NOT changed a thing!

To change the default to 3.11, i.e. to have alternatives reconfigure the symbolic links to point to 3.11, do this:

1.6 priority for alternatives.

As noted above, the three versions of python3 I have on my system have three different priorities. Higher priority numbers means that version will be chosen first, and the highest priority will be chosen as the current best priority.

  • alternatives priority n

1.7 removing an alternative

A simple command will remove a group and all its dependencies. FOr example to remove python3.9, the command is:

  • alternatives --remove <name> <path> # where <name> is the symlink name in
  • sudo alternatives --remove python3 /usr/bin/python3.6

Since python3.6 was NOT the only available slave to me, this command automatically removed the symlink to 3.6 and created a new symlink to the slave with the next highest priority, in my case python3.11. The resultant symlink is now python3 -> /usr/bin/python3.11 and this is what alternatives sees it as:

zintis@acme.org /etc/alternatives[1021]:
$ alternatives --display python3
python3 - status is auto.
 link currently points to /usr/bin/python3.11
/usr/bin/python3.11 - priority 31100
 slave easy_install-3: (null)
 slave pip-3: (null)
 slave pip3: (null)
 slave pydoc-3: /usr/bin/pydoc3.11
 slave pydoc3: /usr/bin/pydoc3.11
 slave pyvenv-3: (null)
 slave python3-man: /usr/share/man/man1/python3.11.1.gz
/usr/bin/python3.9 - priority 3900
 slave easy_install-3: /usr/bin/easy_install-3.9
 slave pip-3: /usr/bin/pip-3.9
 slave pip3: /usr/bin/pip3.9
 slave pydoc-3: /usr/bin/pydoc3.9
 slave pydoc3: /usr/bin/pydoc3.9
 slave pyvenv-3: (null)
 slave python3-man: /usr/share/man/man1/python3.9.1.gz
Current `best' version is /usr/bin/python3.11.
zintis@acme.org /etc/alternatives[1022]:

Easy peasy!!

2 Setting which version to default to

  • alternatives --config python3 will display a list of installed python3 releases and you can choose which to use. Note that this will lock you to that selection. Installing a new higher release will not automatically be used by the system.
    $ sudo alternatives --config python3
    [sudo] password for zintis: 
    
      There are 2 programs which provide 'python3'.
    
      Selection    Command
      -----------------------------------------------
      *+ 1           /usr/bin/python3.11
         2           /usr/bin/python3.9
    
      Enter to keep the current selection[+], or type selection number: 
    
  • alternatives --auto python3 will reset the --config so the system will use what it considers the best release automatically when new releases are installed.