1. 关键概念
先大概阅读一下手册。
有些软件他们的功能相同或类似,能相互替代,比如1)/usr/bin/vi和/usr/bin/ed都是本编辑器,相互之间可以作为替代品使用;再比如,2)gcc 4.2和gcc 9.2只是版本不同,更是明显的互相替代软件;3)OpenJDK和Oracle JDK以及它们的不同版本都是可以互相替代的。alternatives 系统就是用来解决这些问题的。
以1)为例,可以把/user/bin/vi设为整个系统的默认编辑器,一种方式是,创建符号链接/usr/bin/editor使其默认指向/usr/bin/vi,其他用户和程序使用编辑器的使用只需要调用editor命令即可;当管理员想要更改默认编辑器时,简单的更改/user/bin/editor的指向就行了。
扯两句闲话,像1)这种简单的情形手动完成也很方便,但是a)如果程序多起来的时候,纯靠手工管理容易混乱、忘记;b)有些软件同时包含多个可执行文件,它们的切换应该是整体切换,手动容易乱;c)手工切换要求管理者对软件有十分透彻的理解,否则搞错了怎么办,比如弄错了软件和文档的对应关系,但如果有alternatives系统,然后大家都遵守它的使用规则,让软件发行者负责管理软件中各部分的关联关系,然后一起打包进RPM发行包中,就能大大减轻管理员的负担。
回到正题,1)在alternatives会这样实现/usr/bin/editor—>/etc/alternatives/editor–>/usr/bin/vi,就是在/etc/alternatives/目录下多加了一层间接的符号链接。vi和ed都是文本编辑器,并用/user/bin/editor指向其中的一个,在alternatives系统里,我们说软件vi和ed有相同的通用名(generic name):editor,并把/usr/bin/editor称为链接(link),把/usr/bin/vi和/usr/bin/ed都叫做路径(path);这是最基本的情况。而向gcc这样的软件包含多个可执行程序gcc、g++,这就有了master、slave 链接的概念。
一个generic name下包含多个互相替代品(alternatives),每个互相替代品也叫一个组(group),一个组由至少一个主链接和零至多个从链接组成。

alternative directory:/etc/alternatives:这里保存alternative系统中中间那一层符号链接。
自动模式和手动模式:一个generic name第一次安装后,它处于自动模式;一旦手动设置某个组为默认组,它就变成了手动模式,并一直保持手动模式,直到显式使用命令把他设为自动模式。自动模式的含义是:alternatives系统会在安装、卸载软件时自动更新相关链接;而手动模式下,系统不会对链接做任何修改,一切都由系统管理员说了算。
# 1. --install 新注册一个group到generic name中 # alternatives --install link name path priority[--slave slink sname spath]... $ sudo alternatives --install /usr/bin/gcc gcc /usr/local/bin/gcc 4 --slave /usr/bin/g++ g++ /usr/local/bin/g++ # 2. --display name 显示某个通用名字中包含的组以及各个组的优先级、主从链接 # 3. --list 列出alternative系统中所有的组 $ alternatives --list $ alternatives --dispaly gcc # 4. --config name 交互式更改某个通用名字中的默认组;也可以 # 5. --set name path 直接设置默认组(这里的path是组中的master link的实际路径) # 6. --auto name 把name的模式设为自动 # 7. --remove name path 删除某个组 # 由此可见,在命令行中,name + path 可以唯一标识一个组。
2. 做个实验
2.1 环境
$ cat /etc/redhat-release CentOS Linux release 7.7.1908 (Core) $ uname -r 3.10.0-1062.4.1.el7.x86_64 $ alternatives --version alternatives version 1.7.4
2.2 注册并执行命令
alternatives --install <link> <name> <path> <priority>
其中,
- install表示安装
- link是符号链接
- name则是标识符
- path是执行文件的路径
- priority则表示优先级
# 1. 创建文件,模拟三个可互相替代的的“程序” mkdir -p /usr/bin/t0 && cd /usr/bin/t0 [root@lcs2 t0]# cat t0 #/bin/bash echo hello, t0, $(date +%F) [root@lcs2 t0]# cat t1 #/bin/bash echo hello, t1, $(date +%F) [root@lcs2 t0]# cat t2 #/bin/bash echo hello, t2, $(date +%F) # 2. 赋予执行权限 [root@lcs2 t0]# chmod a+x t? [root@lcs2 t0]# ll total 12 -rwxr-xr-x 1 root root 39 2月 1 20:47 t0 -rwxr-xr-x 1 root root 39 2月 1 20:46 t1 -rwxr-xr-x 1 root root 39 2月 1 20:46 t2 # 3. “安装”到alternatives中 [root@lcs2 t0]# alternatives --install /usr/bin/t t /usr/local/t0/t0 10 [root@lcs2 t0]# alternatives --install /usr/bin/t t /usr/local/t0/t1 20 [root@lcs2 t0]# alternatives --install /usr/bin/t t /usr/local/t0/t2 30 # 执行命令 t [root@lcs2 t0]# t hello, t2, 2021-02-01
Opt:安装的时候, 的基本名和 不必相同。
[root@lcs2 t0]# alternatives --install /usr/bin/t0 my-t0 /usr/local/t0/t0 0 [root@lcs2 t0]# alternatives --install /usr/bin/t0 my-t0 /usr/local/t0/t1 10 [root@lcs2 t0]# alternatives --display my-t0 my-t0 - status is auto. link currently points to /usr/local/t0/t1 /usr/local/t0/t0 - priority 0 /usr/local/t0/t1 - priority 10 Current `best' version is /usr/local/t0/t1.
2.3 查看
# 4. 查看 alternatives 怎么说 [root@lcs2 t0]# alternatives --display t t - status is auto. link currently points to /usr/local/t0/t1 /usr/local/t0/t0 - priority 10 /usr/local/t0/t1 - priority 20 /usr/local/t0/t2 - priority 30 Current 'best' version is /usr/local/t0/t2
2.4 切换
[root@lcs2 t0]# alternatives --set t /usr/local/t0/t1 [root@lcs2 t0]# t hello, t1, 2021-02-01 [root@lcs2 t0]# alternatives --display t t - status is manual. link currently points to /usr/local/t0/t1 /usr/local/t0/t0 - priority 10 /usr/local/t0/t1 - priority 20 /usr/local/t0/t2 - priority 30 Current `best' version is /usr/local/t0/t2.
[root@lcs2 t0]# alternatives --set my-t0 /usr/local/t0/t2 /usr/local/t0/t2 has not been configured as an alternative for my-t0
另一种切换的方式是,--config,会进入交互模式。
[root@lcs2 t0]# alternatives --display t t - status is auto. link currently points to /usr/local/t0/t2 /usr/local/t0/t0 - priority 10 /usr/local/t0/t1 - priority 20 /usr/local/t0/t2 - priority 30 Current 'best' version is /usr/local/t0/t2. [root@lcs2 t0]# alternatives --config t There are 3 programs which provide 't'. Selection Command ----------------------------------------------- 1 /usr/local/t0/t0 2 /usr/local/t0/t1 *+ 3 /usr/local/t0/t2 Enter to keep the current selection[+], or type selection number: 2 [root@lcs2 t0]# alternatives --display t t - status is manual. link currently points to /usr/local/t0/t1 /usr/local/t0/t0 - priority 10 /usr/local/t0/t1 - priority 20 /usr/local/t0/t2 - priority 30 Current 'best' version is /usr/local/t0/t2.
2.5 删除
# 1. 删除,并查看 [root@lcs2 t0]# alternatives --remove t /usr/local/t0/t2 [root@lcs2 t0]# alternatives --display t t - status is manual. link currently points to /usr/local/t0/t1 /usr/local/t0/t0 - priority 10 /usr/local/t0/t1 - priority 20 Current 'best' version is /usr/local/t0/t1. # 2. 如果删除当前生效的命令, [root@lcs2 t0]# alternatives --remove t /usr/local/t0/t1 # 会自动在剩余的命令中选择,并切换为自动模式。 [root@lcs2 t0]# alternatives --display t t - status is auto. link currently points to /usr/local/t0/t0 /usr/local/t0/t0 - priority 10 Current 'best' version is /usr/local/t0/t0. # 3. 如果删除时的路径不对,会提示 # alternatives --remove t /usr/bin/local/t0/t0 /usr/bin/local/t0/t0 has not been configured as an alternative for t
3. 更进一步的实验
# 1. 当前是自动模式,使用 t 最终指向 t2 [root@lcs2 t0]# t hello, t2, 2021-02-01 [root@lcs2 t0]# alternatives --display t t - status is auto. link currently points to /usr/local/t0/t2 /usr/local/t0/t0 - priority 10 /usr/local/t0/t1 - priority 20 /usr/local/t0/t2 - priority 30 Current 'best' version is /usr/local/t0/t2. # 2. 跟随路径查看一下 [root@lcs2 t0]# ll $(which t) lrwxrwxrwx 1 root root 19 2月 1 21:29 /bin/t -> /etc/alternatives/t [root@lcs2 t0]# ll /etc/alternatives/t lrwxrwxrwx 1 root root 16 2月 1 21:29 /etc/alternatives/t -> /usr/local/t0/t2
链接指向是:/bin/t -> /etc/alternatives/t -> /usr/local/t0/t2
做个切换,观察链接:
# 1. 设置 [root@lcs2 t0]# alternatives --set t /usr/local/t0/t0 [root@lcs2 t0]# t hello, t0, 2021-02-01 [root@lcs2 t0]# alternatives --display t t - status is manual. link currently points to /usr/local/t0/t0 /usr/local/t0/t0 - priority 10 /usr/local/t0/t1 - priority 20 /usr/local/t0/t2 - priority 30 Current 'best' version is /usr/local/t0/t2. # 2. 跟随路径查看 [root@lcs2 t0]# ll $(which t) lrwxrwxrwx 1 root root 19 2月 1 21:35 /bin/t -> /etc/alternatives/t [root@lcs2 t0]# ll /etc/alternatives/t lrwxrwxrwx 1 root root 16 2月 1 21:35 /etc/alternatives/t -> /usr/local/t0/t0
链接指向是:/bin/t -> /etc/alternatives/t -> /usr/local/t0/t0。
可以认为,到 /etc/alternatives 目录下的链接是固定的,变化的是 /etc/alternatives
中链接的指向。
4. master 和 slave 的实验
4.1 创建几个文件,模拟master-slave命令
[root@lcs2 ms]# ls m1 s1a s1b s1c [root@lcs2 ms]# cat * #!/bin/bash echo master-1 #!/bin/bash echo slave-1-a #!/bin/bash echo slave-1-b #!/bin/bash echo slave-1-c [root@lcs2 ms]# ./m1 master-1 [root@lcs2 ms]# ./s1a slave-1-a [root@lcs2 ms]# ./s1b slave-1-b [root@lcs2 ms]# ./s1c slave-1-c [root@lcs2 ms]# ./m2 master-2 [root@lcs2 ms]# ./s2a slave-2-a [root@lcs2 ms]# ./s2b slave-2-b [root@lcs2 ms]# ./s2c slave-2-c
4.2 注册、切换、执行(待续)
# 1. 注册 [root@lcs2 ms]# alternatives --install /usr/bin/m m /usr/local/ms/m1 10 \ --slave /usr/bin/sa sa /usr/local/ms/s1a \ --slave /usr/bin/sb sb /usr/local/ms/s1b \ --slave /usr/bin/sc sc /usr/local/ms/s1c [root@lcs2 ms]# alternatives --install /usr/bin/m m /usr/local/ms/m2 20 \ --slave /usr/bin/sa sa /usr/local/ms/s2a \ --slave /usr/bin/sb sb /usr/local/ms/s2b \ --slave /usr/bin/sc sc /usr/local/ms/s2c # 2. 查看 [root@lcs2 ms]# alternatives --display m m - status is auto. link currently points to /usr/local/ms/m2 /usr/local/ms/m1 - priority 10 slave sa: /usr/local/ms/s1a slave sb: /usr/local/ms/s1b slave sc: /usr/local/ms/s1c /usr/local/ms/m2 - priority 20 slave sa: /usr/local/ms/s2a slave sb: /usr/local/ms/s2b slave sc: /usr/local/ms/s2c Current 'best' version is /usr/local/ms/m2. # 3. 调用/执行命令 [root@lcs2 ms]# m master-2 [root@lcs2 ms]# sa slave-2-a [root@lcs2 ms]# sb slave-2-b [root@lcs2 ms]# sc # 4. 切换 [root@lcs2 ms]# alternatives --set m /usr/local/ms/m1 # 5. 查看,从命令也一起切换了 [root@lcs2 ms]# alternatives --display m m - status is manual. link currently points to /usr/local/ms/m1 /usr/local/ms/m1 - priority 10 slave sa: /usr/local/ms/s1a slave sb: /usr/local/ms/s1b slave sc: /usr/local/ms/s1c /usr/local/ms/m2 - priority 20 slave sa: /usr/local/ms/s2a slave sb: /usr/local/ms/s2b slave sc: /usr/local/ms/s2c Current 'best' version is /usr/local/ms/m2. # 6. 调用,切换确实生效了 [root@lcs2 ms]# m master-1 [root@lcs2 ms]# sa slave-1-a [root@lcs2 ms]# sb slave-1-b [root@lcs2 ms]# sc slave-1-c # 删除 alternatives --remove m /usr/local/ms/m1 alternatives --remove m /usr/local/ms/m2
5. 附:alternatives 和 java
# 当前java版本 $ java -version openjdk version "1.8.0_232" OpenJDK Runtime Environment (build 1.8.0_232-b09) OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode) # java 确实在 alternatives 命令的管控之下 $ alternatives --list | grep java servlet auto /usr/share/java/tomcat-servlet-3.0-api.jar java auto /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre/bin/java jre_openjdk auto /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre jre_1.8.0 auto /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre jaxp_transform_impl auto /usr/share/java/xalan-j2.jar jaxp_parser_impl auto /usr/share/java/xerces-j2.jar javac auto /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/bin/javac java_sdk_openjdk auto /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64 java_sdk_1.8.0 auto /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64 java_sdk_1.8.0_openjdk auto /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64 # 每次执行java命令,它对应的是这个 $ which java /usr/bin/java # 实际路径是 $ realpath /usr/bin/java /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre/bin/java # /usr/bin/java 是符号链接,指向 /etc/alternatives/ 目录下的同名文件 $ ll /usr/bin/java lrwxrwxrwx 1 root root 22 10月 26 07:38 /usr/bin/java -> /etc/alternatives/java # /etc/alternatives/java 也是符号链接,它指向真正的java文件 $ ll /etc/alternatives/java lrwxrwxrwx 1 root root 73 10月 26 07:38 /etc/alternatives/java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre/bin/java $ echo $PATH /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/
- 切换jdk版本不仅仅是切换一个java命令那么简单,还有对应的javac、javah、javap等等一系列相关命令,怎么处理
- gcc不仅仅是一个gcc命令,还有对应的头文件
6. misc
约定
Ubuntu 上的 update-alternatives
Q. 为什么在 /etc/alternatives 加一层链接?
Q. alternaitives 管理不同替代品的时候为什么要在/etc/alternatives目录下多加一层间接的符号链接呢?
man 手册页有简单说明,说是这样的好处是所有的配置文件都在/etc/目录下,详细的优点参考FHS。
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 administra tor’s changes can be confined within the /etc directory: the FHS (q.v.) gives reasons why this is a Good Thing.
Q. 按道理,OpenJDK和Oracle都应该使用同一个通用名字,但实际情况不是,什么java、jre、openjdk、乱七八糟的。
ref
使用Linux的alternatives命令替换选择软件的版本
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205070.html原文链接:https://javaforall.net
