Debian Linux包管理机制

Posted createchance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Debian Linux包管理机制相关的知识,希望对你有一定的参考价值。

Debian是linux史上的一个非常重要的发行版(话说,笔者写这篇博客时使用的系统就是Debian 8.6,嘿嘿~~在工作中使用debian这两年来,感觉debina是异常稳定哦,注意是异常稳定,至少我这里从来没有出现过各种奇怪的灵异现象~~),这个发行版本是很多Linux的上游版本,比如Ubuntu等著名发行版。Debian的地位的取得不仅仅是因为它创造了一个坚如磐石的Linux发行版,更多的原因在于它确立了一种Linux世界的应用包的构建,发行,管理一套流程的规范和标准,这就是deb包标准(Linux世界有两大软件包标准,一个是RPM,另一个就是DEB)。本篇博文就梳理下有关deb包的各种知识。
需要说明的是,本篇博文的内容整理自debian的官方handbook,debian people,debian wiki的一些文章,文章中图比较多,如果看不清楚,请下载下来查看哦。Debian的handbook我已经上传的到我的百度网盘,大家可以下载(你也可以去官方下载,但是网速好像不太好):
链接: https://pan.baidu.com/s/1qYfJDvQ 密码: c2r7
debian people的链接如下:
https://people.debian.org/~srivasta/MaintainerScripts.html(信息非常全面,建议看这个)
https://wiki.debian.org/MaintainerScripts
××××××××××××××××××××××××××××××××××××××××××××分割线××××××××××××××××××××××××××××××××××××××××××××××××××××

Deb包的组成结构

Deb包都是以deb为后缀名的文件,并且按照debian项目的定义,deb包有两种形式:binary和source。顾名思义,binary就是二进制格式的,这个格式的包中的内容全部都是二进制的,也就是源代码经过编译之后的,可执行或者可链接平台相关的二进制文件。source格式的就是包中有程序的源代码,这部分的内容在安装到机器上之前是需要进行编译的。下面,我们将这两个类型的包都进行一下结构分析。

Binary格式

想要查看一个deb包中的都有哪些内容,可以使用ar这个命令(命令具体用法请man),下面我们以unetbootin_575-1_amd64.deb这个包为例看下这个包中都有那些内容:
首先,我们使用ar命令查看其中内容:

可以看到,这个 包中的有三个文件,现在我们使用ar命令将这些内容解压出来:

现在我们已经把包中的内容解压出来了,我们发现多了debian-binary,control.tar.gz,data.tar.gz这三个文件,其中有两个是压缩文件。我们首先来查看debian-binary这个文件是什么:

原来这个文件是一个纯文本文件,内容只有2.0这个字符串。这里的2.0是什么意思呢?这个的意思是这个deb包使用的格式版本,自2015之后的deb格式全面升级到2.0版本了。这个是开发者在使用debian官方工具打包的时候自动生成的。
现在,我们来看下剩下的2个压缩是什么。首先我们查看control.tar.gz中的内容:

我们把control压缩包中的内容解压到control目录下,并且这个目录下生成了4个文件。我们挨个看下,首先查看control文件:

可以看到,这个control文件也是一个纯文本文件,并且其中的内容记述了这个包的各种详细信息,比如包名,版本,支持的架构,维护者,安装大小,依赖,建议安装包,功能描述等等重要信息。这些信息都是给系统包管理工具看的(准确来说是dpkg工具,后面我们会介绍它)。可以这么理解,这个control文件就向一个deb安装包的身份证件,其中包含了关于这个包的详细说明,至于这些每项说明是什么含义,我们后面会详细说明。
接下来我们再来看看md5sum文件:

这个文件也是一个纯文本文件,从名字上可以看出,这个文件应该是一个MD5摘要的记录文件,用于核验文件是不是被篡改了。这个文件中记录了这个包会安装的所有文件的md5校验值。
接下来,我们在看看postinst这个文件:

这个文件是一个POSIX的脚本文件,看到其中的执行内容是由dh_installmenu工具自动添加的,主要用于更新debian的menu系统,关于debian menu system的信息请查看:
https://www.debian.org/doc/packaging-manuals/menu.html/
因为这部分的内容是打包工具自动添加的,因此内容我们可以暂时不去关心。需要注意的是这个文件的作用,从名字上看这个文件就是在安装完成之后做的事情(postinst = post install),实时上确实如此。
同样滴,postrm这个文件就是在remove之后执行的脚本文件,内容如下:

到此,我们就弄清楚了control压缩包中的内容了。现在我们看下data压缩包中的内容是什么,我们把这个包中的内容解压到data目录下:

这里的内容我们看起来就比较熟悉了,这不就是安装之后的全部的数据吗???对的,这就是安装的数据文件,安装的过程中其实就是把这些数据抽取出来到你的系统中去!!我们可以做这件事情,我们直接执行解压出来的usr/bin目录下的可执行文件:

看见没有?他们是可以直接运行的,所有这就是安装的文件!!

package包的元数据—control文件信息

上面我们见识到了control文件中的信息,现在我们详细说明一下这个文件中的信息的含义。这个文件的记录的信息,我们称之为包的元数据信息,我们可以不用通过解压一个包的方式来查看control信息,我们可以通过apt-cache命令来查看某个包的元信息(这里我们以apt这个包本身为例,因为这个包的信息比较全):

下面我们来介绍一下重点的信息。

依赖信息:depends数据域

这个数据域记录了这个包中的程序需要基于的一些系统库,或者三方库,没有这些库的话,这个包中的程序可能无法运行或者功能不完整。比如上图中我们的apt这个包依赖了manpages-it等包。因为每个包都会有自己的版本,因此在指出依赖的时候还必须要说明依赖的版本信息,版本信息使用一下规则指明:
<<:表示需要小于这个版本的包
<=:表示需要小于等于这个版本的包
=:表示需要等于这个版本的包
>=:表示需要大于等于这个版本的包
>>:表示需要大于这个版本的包
同时,对于包之间的关系,存在与和或的关系,比如某个包需要A或者B,和C包的话,这里的以来可以写成:A | B, C,也就是说使用“|”来表示或的关系,“,”表示与的关系。包和包之间的依赖关系是linux世界软件之间的基本逻辑关系,是构建linux用户空间的重要逻辑。但是依赖逻辑还有另外一个重要用途,那就是用于构建一个软件体系。什么意思呢?我们可以这样,直接构建一个空包,这个包中没有安装的文件,只有一堆的依赖关系,这样的话,如果安装了这个包的话,就相当于安装了这个包中的所有的依赖包,这个包本身并不会产生任何影响。这样的包有很多,比如大名鼎鼎的gnome, kde-full和Linux-image-amd64等等,这些包本身没有东西,只是知己包含了大量的依赖内容。如果不这样写的话,将所有的内容都放到这个包中的话,这个包会异常庞大,拿kde-full来说的话,这个包包含了kde桌面系统的所有部件,整个内容加起来1G多。。。。。。

Recommends,suggests和enhance数据域

Recommends,suggests数据域描述的依赖内容不是强制的。重要的是,recommend数据的依赖虽然不是强制的,但是却是包功能完整发挥必不可少的部件。按照debian policy来说的话,如果你没有足够的理由证明你真的不需要这些Recommend包的话,你一定要安装他们。相反的是,suggest部分的包是给这个包的功能进行锦上添花的,比如说这个包可以让你的软件字体更加好看等等。这部分的包按照debian policy的说法就是:如果你没有足够的理由证明你确实需要这些包,那么你就不要安装他们。enhance部分描述的也是一种依赖关系,但是这种依赖关系是最弱的,这部分的包基本上就是一切增强功能的包,比如软件的插件,主题,美化字体等等。

Conflicts数据域

这个数据域描述的包就是不能和本包同时存在于一个系统中的包,他们之间是逻辑上冲突的。最常见的情形就是这些包中都包含同样名称的文件,或者提供同样的系统服务(比如监听在同一个TCP端口上),或者相互之间的业务逻辑冲突的。
dpkg软件管理系统会拒绝和目前已经安装软件冲突的软件包,并且通过给出错误告警信息,除非这个包申明它会覆盖(replace)和它冲突的包,这样的情况下dpkg会使用新的包来替换已经存在的包文件。

Breaks数据域:不兼容描述

这部分数据的描述和conflicts描述的内容有点相似,但是含义上有些许不同。这部分指出,安装这个包会破坏(break)另外一个已经安装的包。两个包之间的不兼容关系是短暂的,并且break关系通常明确指明不兼容的软件包的版本。
同样的,dpkg也会拒绝安装和现有安装包有break关系的包,不用的是apt工具会尝试去解决这个问题,比如升级有break关系的软件包到一个兼容的版本。
通常,这种情况会出现在系统升级了一个不向后兼容的包的时候,这些新版本的软件可能不在提供旧版本的某些功能。这个时候break关系会保证系统不会进入到这样的问题中,因此压根就不会安装他们或者解决这个问题。

Provides数据域

这个涉及到一个deb包中非常有趣的一个概念:虚拟包。这个包在系统中有很多角色,其中最重要的角色有两个。第一个是利用虚拟包来申明提供一个系统服务,第二个是指明一个包完全取代了另一个,这样的话就可以满足其他依赖包的依赖关系。下面我们看下这两个角色的含义。

提供一个服务

这里我们举一个简单的例子,在linux中,有好几个包都可以提供email投递服务,比如:postfix, sendmail等。这些包虽然名字都不一样,但是都会提供一个这样的服务:mail-transport-agent,这个服务的存在就是一个虚拟包。这个包并不实际存在,但是系统中确实有这个包。这样的话,如果你的系统安装了一个邮件投递服务包的话,那么如果你想再次安装另外一个的话,系统会报错,因为系统中已经有包可以提供相同的系统服务了。这样可以防止系统中安装了大量相同功能的包,可以很好地防止系统过分臃肿。

和其他包之间的互换性

我们举一个perl语言模块的例子,libdigest-md5-perl在Perl 5.6之前是一个可选的包,但是在Perl 5.8之后就是一个系统默认自带的包。在这个情况下,Perl 5.8版本的运行环境可以申明一个libdigest-md5-perl的虚拟包,这样的话,基于libdigest-md5-perl这个包的旧版本的应用程序任然可以运行,另外用户升级的时候,libdigest-md5-perl这个实际的包也会被移除,因此系统中老版本的Perl已经移除了,新版本中的自带这个包中的功能,因此他也就没有存在的必要了,会被自动删除。描述的情况如下图:

这里需要说明的是,元数据包和虚拟包是不一样的,虽然他们在逻辑上有点相似。元数据包是实际存在的一个deb包,虽然它里面什么都没有。而虚拟包是实际不存在的,只是逻辑上的一个东西。同时,虚拟包的名字也不能随意定义,为了避免虚拟包名的混乱,debian项目组定义了一个目前的虚拟包名的名称列表,因此如果你要开发一个包的话,请注意不要和这个列表中的名字重复:
https://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt

Replaces数据域

这个数据域描述的信息说明了这个包中的某些文件会替换系统中已经存在的文件所属于的包,但是这个替换行为是合法的。如果没有这个声明的话,那么dpkg会拒绝安装这个包,因为可能这个包会破坏当前的系统(虽然你可以使用–force-overwrite选项来强制覆盖,但是这终究不是一个靠谱的做法)。
这个数据域的通常使用场景就是软件包的升级,一个新的版本可能完全覆盖老版本的所有文件,然而这一切是合法,合理的。

Source格式

一个source合适的软件包,通常都由3个文件组成:一个.dsc文件,一个.orig.tar.gz文件,一个.debian.tar.gz(或者.diff.gz)文件。我们可以从source包构建deb二进制包,这些source包中的数据就是使用程序语言编写的源代码。我们可以从163的镜像源中看下source格式的软件包和deb二进制的文件包 ,这里我们以abx这个软件包为例:

可以看到,上图中有各个硬件架构的deb二进制软件包,剩下的就是source软件包了。那些deb的二进制包都是使用source包编译构建出来的。
下面我们看下这3个文件都是什么内容,首先我们看下dsc文件,dsc是Debian Source Control的简写,是一个纯文本文件,类似于上面deb的control文件,这个文件使用了RFC 2822标准的数据格式,描述了source包的元数据信息。通常如下内容,还是以上面的abx包为例:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Format: 3.0 (quilt)
Source: abx
Binary: abx
Architecture: any
Version: 0.0~b1-1
Maintainer: Chow Loong Jin <hyperair@debian.org>
Homepage: http://phintsan.kapsi.fi/abx.html
Standards-Version: 3.9.4
Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1), dh-autoreconf, autoconf-archive, portaudio19-dev, libsndfile1-dev, libgtk2.0-dev
Package-List: 
 abx deb sound extra
Checksums-Sha1: 
 20577adf12245c7b3b2d9a2383a8e90f846710f2 156146 abx_0.0~b1.orig.tar.gz
 b7c153e9999f4c781c23bd76a71034995dcc83cf 2311 abx_0.0~b1-1.debian.tar.gz
Checksums-Sha256: 
 66ceb8e8408ad5f75e1c6b0507ebcbc8963676659a8bebdf1e595fafefd07f1f 156146 abx_0.0~b1.orig.tar.gz
 f998bee0f1f693f14ad8e0064fdf08b145d24a03e1fd00ba2f4be5e0455b51bc 2311 abx_0.0~b1-1.debian.tar.gz
Files: 
 a42fb6d3d966fccece2af80f8ba8bf0a 156146 abx_0.0~b1.orig.tar.gz
 a1b5e51918101fb40165864e5a12b9b6 2311 abx_0.0~b1-1.debian.tar.gz

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iQIcBAEBAgAGBQJSPYZuAAoJEPvVIltYh1KhH00P/R9kpWoi1ozQNJVNt+wG512o
vZMY6LnxU1dv5AGUEV7XZYJD/xlc+R5hbVMQGnnYUjJK2qpeTlDZUKHxySW9tTsg
Y49x5cOPLUh4J98YMXfGw7jIJpGqCyBiS82jJfnNUregBSIzFG1py7sUmS9fOQf4
enTlJCjq5DceAsrXseqnDP/tzMxreiyD7lSnGkTwNeL5gfXcCmuK0XoOcRV5UGW5
kA855QnHfURRqvhWU9Ach4e+Y3TmRoaaPqIoNJAkoXTpX7vnaEBxJxszbc/u6HW2
RfP60F34c2XSC55T7IGHaS+1OdN+GBSw+/p244eIMtYRFqKUQdFtt/enLGXW717k
7u13RKJBj99G6+AMaoWrZXNvWIRgoB5GVmjuLnfgPz/7L2Bpku0gwy2HnORc9QHx
55fawPzPK26TmGjI9hzkzsNOd/QVGI0Hf+CXjFEx8s/tCiUzqKT2Spfevrq1zD/w
phIh+UrkmOpBrIJ4rzCNePJsr9113BHZJtCr6Q/Fh/u5sx5Vx0M44BnhKDvqLpDb
jlKYtn/+26gDqNF6yPl/8OJHScWkM72GjcHK+vLE5kEAMGMIzCbRbuG+BaGmxL4t
phpnT8S24+X2ux7L17Qfs9EgqmBQ/pJGyBR0lSSphPyNTbLV5ma63MqBVipPCF1x
ibE366O2xfFjreH5RDbk
=P9DT
-----END PGP SIGNATURE-----

可以看到,这个文件中的内容是经过GPG签名的,信息由软件包的开发者或者维护者填写。同时,需要注意的是,source包也是有依赖的,只不过这个依赖是编译时的依赖,这一点和Binary包是截然不同的。这里我们需要进一步说明的是,一个source包可能会编译生成多个deb包。这就是为什么dsc文件中有source和Binary数据域的原因。Binary数据域表示了有多少个deb二进制包会生成。那为什么要将一个source包编译成多个deb包呢?这涉及到系统设计的考量。因为很多的软件包都会对外提供共享库给三方开发者,这样的话,用户就可以选择只安装这个软件包中的部分,也就是共享库的那部分。另外还有一种情况就是,这个软件包是C/S架构的,因此需要编译成server端和client端程序,以便独立安装部署。另外,很多的软件都会在source中提供doc文档,因此文档这部分组要单独编译成一个deb包,然后代码部分编译成不同架构的deb包,这样就不用每个硬件架构的deb包都携带doc内容,因此可以节省服务器上的存储资源。

dpkg工具安装,卸载,升级deb包

dpkg是debian系统中底层的软件包管理程序,他提供了非常基础底层的功能,在它的基础之上人们开发出了很多的上层的,更加易用的软件管理程序,比如apt,aptitude等。
dpkg管理下的所有软件包都处于以下状态之一:
Not-Installed state : 包还没有安装
Config-Files state : 当前只有这个包的配置文件存在于本地系统上
Half-Installed state : 安装中间状态,这个包的安装已经开始了,但是由于某些原因还没有完成安装
Unpacked state : 包已经被解包,但是还没有开始配置
Half-Configured state : 配置中间状态,这个包已经被解包,并且配置也已经开始了,但是由于某些原因这个步骤还没有结束
Triggers-Awaited state : 有其他的包等待这个包的触发操作
Triggers-Pending state : 另一个包已经激活了这个包先前表示感兴趣的触发器,现在有一些工作需要完成
Fully Installed state : 这个包已经被解包,并且正确地配置,这个包已经完全安装
除了上面提到的状态,dpkg还有标记一些特殊的包,目前而言,这些标记的位有:
reinst-required flag:某个包被打上这个标记就意味着这个包已经损坏并且需要重新安装,这些包不能被卸载移除,除非通过强制移除选项:–force-remove-reinstreq。
通常来讲,针对一个包的操作可以是下面的一种:安装,卸载,重新安装,升级。这里我们重点关注安装,卸载和升级deb包的过程,因为其他的过程都是在这个基础之上发展的,基本类似。

安装一个deb包

这里我们说明一下,安装一个包是指这个包目前并没有安装到当前系统上,这个包是全新安装。安装一个包是包管理系统中的最基础,最重要的一个功能,这个过程通常包含以下几个步骤:
1. 从deb包中抽取出control文件
2. 如果当前系统中有这个包的老版本,那么在正式安装这个包之前需要执行老版本包的prerm脚本
3. 运行preinst脚本(如果有的话)
4. 解压deb文件,同事备份旧版本的文件,以便安装出现问题的时候可以回滚到旧版本中。到这一步位置,任何配置都没有进行
5. 如果系统中安装有这个包的旧版本,那么此时运行这个旧版本的postrm脚本。注意,这个脚本是在新包的preinst脚本运行之后运行的,因为新文件已经写入当前系统同时旧版本的文件就被删除。
6. 配置这个包,配置过程包含以下步骤:解压conf文件,同时备份老版本的配置文件,以便出错回滚;然后运行postinst脚本,如果这个脚本有的话。
下面我们使用一个UML的状态图来描述安装的状态(就像上面提到的),图片来自https://people.debian.org/~srivasta/MaintainerScripts.html

这个图描述了安装过程中的操作:当用户要求安装一个包的时候,这个包可能根本就不会安装,会结束在安装过程中状态,上图中只有绿色的状态才是成功的一个状态。
上面我们提到了很多的配置文件,下面我们给出一张图来解释各种配置文件的调用过程(图片来自https://wiki.debian.org/MaintainerScripts):

我们简单解释一下这个图,当一个包被安装的时候,首先preinst install会被调用,然后就是postinst configure,如果一切顺利的话,然后这个包的状态就是installed。但是如果在preinst install期间除了什么问题,那么postrm abort-install会调用。如果调用成功的话,用户会得到一个错误信息,提示安装失败,并且这个包的状态就是not installed。但是如果postrm abort-install也失败了,这个包就会进入一个比较尴尬的状态:half install,也就是安装了一半的状态,这个时候这个包是需要重新安装的,除非你使用上面提到的强制卸载选项,否则你得重新安装这个包。如果在postinst configure期间出错了,用户也会得到一个错误信息,兵并且这个包的状态就是Failed-Config状态。
为了有一个全面的安装过程理解,我们下面给出安装过程的全部过程图(来自https://people.debian.org/~srivasta/MaintainerScripts.html):

这个图中描述的deb安装版本是V1版本,绿色的部分就是正常情况下deb包应该处于的状态。维护脚本文件是在菱形的选择框中执行的,因为后续的结果取决于这个脚本执行是否成功。同时这个图中只是描述了安装的主体过程,没有给出依赖解决,冲突解决等过程。

卸载一个deb包

同样地我们这里说的卸载是指卸载一个已经正确完整安装的包。还需要说明的是,卸载一个包默认情况下是不会删除这个包的配置文件的,除非用户明确说明(加上purge选项,这个选项的意思就是移除和这个包有关的所有东西!!慎用!!)。如果没有加上purge选项的话,系统在下次安装这个包的时候,并不会重新配置这个包,而是直接使用这个包已有的配置。如果没有说明–purge的话,卸载包含以下步骤:
1. 执行prerm脚本
2. 移除安装的文件
3. 执行postrm脚本
下面是卸载一个包的时候的系统状态流转图(来自https://people.debian.org/~srivasta/MaintainerScripts.html):

同样这个途中正常状态就是绿色部分的状态,从installed到not installed状态。
下图是维护脚本的调用过程,不使用purge(来自https://wiki.debian.org/MaintainerScripts):

这个图的解释和理解和安装的一样。下面是使用–purge的情况,大体类似,只是多了移除配置文件的过程:

两个图合起来的状态就是下面这样,也就是用户执行apt-get purge 包名的情形:

这里需要说明的是,如果用户卸载包的时候没有使用purge选项,也即是说这个包的配置文件被保留了下来,因此下次安装的时候,系统会跳过重新配置的步骤,直接使用系统中原有的配置:

注意上图中的postinst configure 1.2-3中的1.2-3指明了使用现有系统中旧版本的配置文件。
下面我们使用流程图整体描述卸载软件包的过程(来自https://people.debian.org/~srivasta/MaintainerScripts.html):

升级一个deb包

升级一个包是指这个包已经在当前系统中正确安装,现在有一个新的版本需要升级。一个软件包的升级过程是比较复杂的,步骤较多。
下面我们首先给出这个步骤中的状态描述图:

这个图描述了从V1升级到V2的过程。
下面我们给出一个将foo包从1.2-3版本升级到1.2-4版本的过程:

你可以看到,升级的过程中中间步骤非常多,但是上面的图给出了比较直观的描述。
接下来我们还是给出升级的全部流程图:

包维护脚本的执行状态图

上面我们描述了很多的包维护脚本,下面我们给出包在安装,卸载,升级等过程中的所有脚本执行图:

dpkg的数据库

到现在为止,大家应该对deb包的管理过程有一个大致的了解了,现在我们来想一个问题,我们在系统中随时都可以查询一个已经安装的包的状态,那么这些信息是存在哪里的呢?另外,我们上面提到的deb的维护脚本,这些脚本又是存储在系统的什么位置的呢?这些都是存储在dpkg的database里面,这个数据库并不是我们理解的sql的数据库,而是一个专用的系统目录,这个目录下存储了很多关于包管理的信息,这个目录就是/var/lib/dpkg。我们先看下这个目录下都有什么,以我的电脑为例(debian 8.6):

可以看到,这个目录下保存了很多的信息,其中需要注意的就是info目录,lock文件,status文件。info目录下存储就是系统中所有安装包的信息,包括包的control信息,维护脚本,md5校验值等信息:

这里我们以xterm包为例,info目录下保存了它的配置文件信息文件,安装文件信息文件,md5校验值文件,维护脚本文件。大家可以到自己的系统目录下查看这些文件的内容。

APT工具集合

APT是一个很庞大的开源的deb包管理项目,他提供了apt-get,apt-cache,apt等著名的上层用户友好的包管理工具,这个工具是基于dpkg系统的,因此只是在dpkg的基础之上封装了一套用户友好的逻辑。
更多关于apt的信息请看官网:https://wiki.debian.org/Apt,笔者后期会持续更新这部分的内容。

其他高级工具

debian系列系统的魅力就在于他提供了丰富多彩的高级包管理工具,按照debian官网的说明,这些高级工具有以下内容(来自https://www.debian.org/doc/manuals/debian-reference/ch02.en.html):

除了上面的工具之外,这里笔者强烈给大家推荐一个上面没有列出的管理软件gdebi,这个软件在解决包的依赖上非常出色,可以省去很多的烦恼,这个工具是使用python语言开发的,逻辑简单明了,项目地址:
https://launchpad.net/gdebi
大家可以去上面看看文档,非常简单易用。

以上是关于Debian Linux包管理机制的主要内容,如果未能解决你的问题,请参考以下文章

APT是啥?

linux包管理(11)

Linux 发行版本

Linux 发行版本

详解Linux软件安装中RPM与YUM 区别和联系

debian11用哪种桌面环境