2022年2月17日星期四

Linux备胎系统(update-alternatives)

 

简介

Debian操作系统中提供了一套备胎系统(alternatives system)用来维护系统中具有同样功能的多个不同备胎程序。不同的备胎程序可以是具有相同功能的不同程序,也可以是同一个程序的不同版本,如Oracle jdkopenjdk,或 jdk8jdk11等。

譬如系统上同时安装了文本编辑器vivimnano,那么在使用时我们可以通过不同的名称来执行,也可以创建名称为editor的符号链接来管理多个文本编辑器,通过update-alternatives命令来安装、设置editor指向的目标。

机制

名称为editor的符号链接并不直接指向实际的文本编辑器程序,而是指向备胎目录(alternatives directory)下的符号链接,再由备胎目录下的符号链接指向实际使用的目标文本编辑程序。

譬如我的Ubuntu 20系统中,名称为editor的符号链接路径为/usr/bin/editor,指向了/etc/alternatives/editor,而/etc/alternatives/editor又指向实际使用的链接目标/bin/nano

$ ll /usr/bin/editor
lrwxrwxrwx 1 root root 24 Feb 13 20:07 /usr/bin/editor -> /etc/alternatives/editor*
$ ll /etc/alternatives/editor
lrwxrwxrwx 1 root root 9 Feb 13 20:07 /etc/alternatives/editor -> /bin/nano*

主/从符号链接

一个符号链接实际可用包含一个主链接和多个从链接,切换链接目标时,主从链接目标同时切换,譬如java可用包含javacjavahjar等多个附属工具,创建java符号链接时可以将附属工具作为从属符号链接,这样在切换jdk版本时,附属工具也一同切换。

update-alternatives

备胎系统使用update-alternatives命令用来查看、增删修改符号链接所指向的目标。命令格式为:

update-alternatives [option...] command

下面以常用的javapython3来示范其用法

查看update-alternatives版本号

$ update-alternatives --version
Debian update-alternatives version 1.19.7.

查看符号链接的所有目标--list

update-alternatives --list name

update-alternatives所管理的符号链接都有个名字,--list命令可以查看name所对应的所有链接目标。

$ update-alternatives --list java
/usb/lib/jvm/java-11-openjdk-adm64/bin/java
/usb/lib/jvm/java-8-openjdk-adm64/jre/bin/java

可以看到java有两个链接目标可用

注意:这里只会列出update-alternatives所管理的链接目标;可以通过--install添加新的目标。譬如系统中安装了多个版本的python3,但是并没有使用update-alternatives --install进行安装,则不会被列出。

查看符号链接详细信息

--display

update-alternatives --display name

可用使用--display查看符号链接详细信息:

$ update-alternatives --display java
java - auto mode
  link best version is /usr/lib/jvm/java-11-openjdk-amd64/bin/java
  link currently points to /usr/lib/jvm/java-11-openjdk-amd64/bin/java
  link java is /usr/bin/java
  slave java.1.gz is /usr/share/man/man1/java.1.gz
/usr/lib/jvm/java-11-openjdk-amd64/bin/java - priority 1111
  slave java.1.gz: /usr/lib/jvm/java-11-openjdk-amd64/man/man1/java.1.gz
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java - priority 1081
  slave java.1.gz: /usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz

可用看出以下信息:

  1. 当前java模式为自动模式,即自动选择优先级最高的目标/usr/lib/jvm/java-11-openjdk-amd64/bin/java
  2. java符号链接位于:/usr/bin/java
  3. java有子符号为:java.1.gz,位于:/usr/share/man/man1/java.1.gz
  4. 目标/usr/lib/jvm/java-11-openjdk-amd64/bin/java优先级为1111
  5. 目标/usr/lib/jvm/java-11-openjdk-amd64/bin/java的子符号位于/usr/lib/jvm/java-11-openjdk-amd64/man/man1/java.1.gz
  6. 目标/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java优先级为1081
  7. 目标/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java的子符号位于/usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz

--query

update-alternatives --query name

还可以--query查看,与--display不同的是--query显示的内容便于机器解析使用:

$ update-alternatives --query java
Name: java
Link: /usr/bin/java
Slaves:
 java.1.gz /usr/share/man/man1/java.1.gz
Status: auto
Best: /usr/lib/jvm/java-11-openjdk-amd64/bin/java
Value: /usr/lib/jvm/java-11-openjdk-amd64/bin/java

Alternative: /usr/lib/jvm/java-11-openjdk-amd64/bin/java
Priority: 1111
Slaves:
 java.1.gz /usr/lib/jvm/java-11-openjdk-amd64/man/man1/java.1.gz

Alternative: /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
Priority: 1081
Slaves:
 java.1.gz /usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz

添加符号链接目标

update-alternatives --install link name path priority [--slave link name path]...

可用使用--install命令给符号链接新增链接目标,如果符号链接不存在则创建符号链接。

下面以python3为例示范--install命令

$ ll `which python3`
lrwxrwxrwx 1 root root 25 Feb 14 17:59 /usr/bin/python3 -> /usr/bin/python3.8*
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 380
update-alternatives: using /usr/bin/python3.8 to provide /usr/bin/python3 (python3) in auto mode
$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3. 390
update-alternatives: using /usr/bin/python3.8 to provide /usr/bin/python3 (python3) in auto mode
$ update-alternatives --display python3
python3 - auto mode
  link best version is /usr/bin/python3.9
  link currently points to /usr/bin/python3.9
  link python3 is /usr/bin/python3
/usr/bin/python3.8 - priority 380
/usr/bin/python3.9 - priority 390

可以查看下符号链接的具体目标:

$ ll `which python3`
lrwxrwxrwx 1 root root 25 Feb 14 17:59 /usr/bin/python3 -> /etc/alternatives/python3*
$ ll /etc/alternatives/python3 
lrwxrwxrwx 1 root root 18 Feb 14 18:00 /etc/alternatives/python3 -> /usr/bin/python3.9*

原本符号链接/usr/bin/python3指向/usr/bin/python3.8,现在指向了/etc/alternatives/python3,而/etc/alternatives/python3又指向了最终目标/usr/bin/python3.9

slave从属符号链接

创建带有slave从属符号链接的java符号链接:

$ update-alternatives --display java
java - auto mode
  link best version is /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
  link currently points to /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
  link java is /usr/bin/java
  slave java.1.gz is /usr/share/man/man1/java.1.gz
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java - priority 1081
  slave java.1.gz: /usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz
$ sudo update-alternatives \
--install /usr/bin/java java /usr/lib/jvm/java-17-openjdk-amd64/bin/java 1711 \
--slave /usr/share/man/man1/java.1.gz java.1.gz /usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz
update-alternatives: using /usr/lib/jvm/java-17-openjdk-amd64/bin/java to provide /usr/bin/java (java) in auto mode
$ update-alternatives --display java
java - auto mode
  link best version is /usr/lib/jvm/java-17-openjdk-amd64/bin/java
  link currently points to /usr/lib/jvm/java-17-openjdk-amd64/bin/java
  link java is /usr/bin/java
  slave java.1.gz is /usr/share/man/man1/java.1.gz
/usr/lib/jvm/java-17-openjdk-amd64/bin/java - priority 1711
  slave java.1.gz: /usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java - priority 1081
  slave java.1.gz: /usr/lib/jvm/java-8-openjdk-amd64/jre/man/man1/java.1.gz

这样在切换java链接目标时,从属符号链接java.1.gz的目标也一同切换

切换链接目标

config

update-alternatives --config name

--config将使用交互方式更改指定符号链接的目标:

$ sudo update-alternatives --config python3
There are 2 choices for the alternative python3 (providing /usr/bin/python3).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.9   390       auto mode
  1            /usr/bin/python3.8   380       manual mode
  2            /usr/bin/python3.9   390       manual mode

Press <enter> to keep the current choice[*], or type selection number: 

可以看到出现了交互式界面,列出了所有候选目标供选择,其中第0项为自动模式,选择该项则自动选择最优目标,即优先级最高的目标。第12项则为前面--install的两个目标。

切换目标为1:

...
Press <enter> to keep the current choice[*], or type selection number: 1
    update-alternatives: using /usr/bin/python3.8 to provide /usr/bin/python3 (python3) in manual mode
$ update-alternatives --display python3
python3 - manual mode
  link best version is /usr/bin/python3.9
  link currently points to /usr/bin/python3.8
  link python3 is /usr/bin/python3
/usr/bin/python3.8 - priority 380
/usr/bin/python3.9 - priority 390

--set

update-alternatives --set name path

--set使用非交互方式更改符号链接的目标, 功能等同于--config

$ sudo update-alternatives --set python3 /usr/bin/python3.9
update-alternatives: using /usr/bin/python3.9 to provide /usr/bin/python3 (python3) in manual mode
$ update-alternatives --display python3
python3 - manual mode
  link best version is /usr/bin/python3.9
  link currently points to /usr/bin/python3.9
  link python3 is /usr/bin/python3
/usr/bin/python3.8 - priority 380
/usr/bin/python3.9 - priority 390

--auto

update-alternatives --auto name

设置符号链接name为自动模式,即指向优先级最高的目标

$ update-alternatives --display python3
python3 - manual mode
  link best version is /usr/bin/python3.9
  link currently points to /usr/bin/python3.8
  link python3 is /usr/bin/python3
/usr/bin/python3.8 - priority 380
/usr/bin/python3.9 - priority 390
$ sudo update-alternatives --auto python3
update-alternatives: using /usr/bin/python3.9 to provide /usr/bin/python3 (python3) in auto mode
$ update-alternatives --display python3
python3 - auto mode
  link best version is /usr/bin/python3.9
  link currently points to /usr/bin/python3.9
  link python3 is /usr/bin/python3
/usr/bin/python3.8 - priority 380
/usr/bin/python3.9 - priority 390

--all

update-alternatives --all

--all将使用交互方式更改所有符号链接的目标,即遍历update-alternatives工具所管理的所有符号链接,执行--config操作;只有一个目标的符号链接会被忽略

可以用--skip-auto选项来略过所有auto mode自动模式的符号链接

删除链接目标

--remove

update-alternatives --remove name path

使用--remove命令将path所对应的链接目标从name符号中移除,如果有slave从属链接,也一并移除

列出python3所有目标:

$ sudo update-alternatives --list python3
/usr/bin/python3.8
/usr/bin/python3.9

移除/usr/bin/python3.9

$ sudo update-alternatives --remove python3 /usr/bin/python3.9 
$ sudo update-alternatives --list python3
/usr/bin/python3.8

移除最后一个目标:

$ sudo update-alternatives --remove python3 /usr/bin/python3.8
update-alternatives: removing manually selected alternative - switching python3 to auto mode

查看符号python3信息:

$ sudo update-alternatives --list python3
update-alternatives: error: no alternatives for python3
$ ll /usr/bin/python3
ls: cannot access '/usr/bin/python3': No such file or directory
$ ll /etc/alternatives/python3
ls: cannot access '/etc/alternatives/python3': No such file or directory

可以看到链接文件/usr/bin/python3/etc/alternatives/python3也同时被删除了

--remove-all

update-alternatives --remove-all name

使用--remove-all命令移除符号链接name所有的目标,同时移除关联的所有slave从属目标

列出python3所有目标:

$ sudo update-alternatives --list python3
/usr/bin/python3.8
/usr/bin/python3.9

移除python3所有目标:

$ sudo update-alternatives --remove-all python3

查看符号python3信息:

$ sudo update-alternatives --list python3
update-alternatives: error: no alternatives for python3
$ ll /usr/bin/python3
ls: cannot access '/usr/bin/python3': No such file or directory
$ ll /etc/alternatives/python3
ls: cannot access '/etc/alternatives/python3': No such file or directory

可以看到链接文件/usr/bin/python3/etc/alternatives/python3也同时被删除了

--get-selections--set-selections

update-alternatives --get-selections
update-alternatives --set-selections

使用--get-selections列出所有符号链接目前所选择的目标,输出到标准输出。不包括slave从属符号链接;格式为name mode target

$ update-alternatives --get-selections
arptables                      auto     /usr/sbin/arptables-nft
automake                       auto     /usr/bin/automake-1.16
awk                            auto     /usr/bin/mawk
builtins.7.gz                  auto     /usr/share/man/man7/bash-builtins.7.gz
c++                            auto     /usr/bin/g++
...
python3                        manual   /usr/bin/python3.8
...

--get-selections获取的内容可以从标准输入给--set-selections使用,设置符号链接的目标。

TODO

参看

update-alternatives(1) — Linux manual page

没有评论:

发表评论

Android logcat

Log等级 Android log 等级在 android/log.h 中定义如下: typedef   enum   android_LogPriority {    /** For internal use only. */ ANDROID_LOG_UNKNOWN =...