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 insudo 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 alist 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
willreset
the--config
so the system will usewhat it considers the best
release
automatically when new releases are installed.