第十四章:包管理

如果我们花时间在Linux社区,我们会听到很多关于许多Linux发行版(distributions)中哪一个“最好”的意见。通常,这些讨论会变得非常愚蠢,只关注桌面背景的美观(有些人不会使用Ubuntu,因为它的默认配色方案!)和其他琐碎的事情。

发行版质量最重要的决定因素是包系统(packaging system)和发行版支持社区的活力。随着我们花更多的时间在Linux上,我们看到它的软件环境是非常动态的。事情在不断变化。大多数顶级Linux发行版每六个月发布一次新版本,每天都有许多单独的程序更新。为了跟上这场软件风暴,我们需要好的软件包管理工具(package management)。

包管理是一种在系统上安装和维护软件的方法。如今,大多数人可以通过安装Linux分销商的软件包来满足他们所有的软件需求。这与Linux的早期形成鲜明对比,当时必须下载并编译源代码才能安装软件。编译源代码没有任何问题;事实上,能够访问源代码是Linux的一大奇迹。它使我们(和其他人)能够检查和改进系统。只是拥有一个预编译的包更快、更容易处理。

在本章中,我们将介绍一些用于包管理的命令行工具。虽然所有主要的发行版都提供了强大而复杂的图形程序来维护系统,但了解命令行程序也很重要。它们可以执行许多图形对应物难以(或不可能)完成的任务。

第十四章:包管理包系统包系统如何工作包文件存储库依赖关系高级和低级包工具常见包管理任务在存储库中查找包从存储库安装包从包文件安装包删除包从存储库更新包从包文件升级包列出已安装的软件包确定是否安装了程序包显示有关已安装包的信息查找哪个软件包安装了文件独立于分发的包格式总结Linux软件安装神话

包系统

不同的发行版使用不同的打包系统,一般来说,用于一个发行版的包与另一个发行版本不兼容。大多数发行版分为两个打包技术阵营:Debian .deb 阵营和Red Hat .rpm 阵营。有一些重要的例外,如Gentoo、Slackware和Arch,但大多数其他人使用这两个基本系统中的一个,如下表所示:

包系统发行版(部分列表)
Debian Style(.deb)Debian,Ubuntu,Linux Mint,Raspberry Pi OS
Red Hat Style(.rpm)Fedora,CentOS,Red Hat Linux,OpenSUSE

包系统如何工作

在专有软件行业中发现的软件分发方法通常需要购买一块安装介质,如“安装盘”,或访问供应商的网站并下载产品,然后运行“安装向导”在系统上安装新的应用程序。

Linux不是这样工作的。几乎所有Linux系统的软件都可以在互联网上找到。其中大部分将由发行版供应商以包文件的形式提供,其余部分将以可以手动安装的源代码形式提供。我们将在【第23章.编译程序】中讨论如何通过编译源代码来安装软件。

包文件

包系统中软件的基本单位是包文件(package file)。包文件是组成软件包的压缩文件集合。一个包可能由许多程序和支持这些程序的数据文件组成。除了要安装的文件外,包文件还包括有关包的元数据,例如包及其内容的文本描述。此外,许多软件包都包含安装前和安装后脚本,这些脚本在软件包安装前后执行配置任务。

包文件由称为包维护者(package maintainer)的人创建,通常(但并不总是)是分发供应商的员工。包维护者从上游提供者(upstream provider ,程序的作者)那里获得源代码形式的软件,对其进行编译,并创建包元数据和任何必要的安装脚本。通常,包维护者会对原始源代码进行修改,以改善程序与Linux发行版其他部分的集成。

存储库

repository —— 存储库,仓库,智囊,知识宝典,学识渊博的人

虽然一些软件项目选择执行自己的打包和分发,但今天的大多数包都是由分发供应商和感兴趣的第三方创建的。在中央存储库中,分发版的用户可以使用包,其中可能包含数千个包,每个包都是专门为分发版构建和维护的。

一个发行版可能为软件开发生命周期的不同阶段维护多个不同的存储库。例如,通常会有一个“testing”(测试)存储库,其中包含刚刚构建的包,这些包是为那些在包发布之前寻找bug的勇敢者而设计的。发行版通常会有一个“development”(开发)存储库,其中保存了注定要包含在发行版下一个主要版本中的正在进行的工作包。

发行版也可能有相关的第三方存储库。这些通常需要提供软件,由于专利或DRM反规避(anti-circumvention)问题等法律原因,这些软件不能包含在分发中。也许最著名的案例是加密DVD支持,这在美国是不合法的。第三方存储库在不适用软件专利和反规避法律的国家运营。这些存储库通常完全独立于它们支持的发行版,要使用它们,必须了解它们并手动将其包含在包管理系统的配置文件中。

依赖关系

程序很少是“独立的”(standalone);相反,它们依赖于其他软件组件的存在来完成工作。常见的活动,例如输入/输出,由许多程序共享的例程处理。这些例程存储在所谓的共享库中(shared libraries),共享库为多个程序提供基本服务。如果一个包需要共享资源,如共享库,则称其具有依赖关系(dependency)。现代包管理系统都提供了一些依赖关系解析(dependency resolution)方法,以确保在安装包时,其所有依赖关系也都已安装。

高级和低级包工具

包管理系统通常由两种类型的工具组成。

在本章中,我们将介绍Debian风格系统(如Ubuntu和许多其他系统)提供的工具以及红帽产品使用的工具。虽然所有红帽风格的发行版都依赖于相同的低级程序( rpm ),但它们使用不同的高级工具。在我们的讨论中,我们将介绍Red Hat Enterprise Linux、CentOS和Fedora使用的高级程序 dnf 。其他红帽风格的发行版提供了具有类似功能的高级工具(见下表)。

发行版低级工具高级工具
Debian styledpkgapt、apt-get、aptitude
Fedora、RedHat、CentOSrpmdnf、yum

常见包管理任务

许多操作都可以使用命令行包管理工具执行。我们将看看最常见的。请注意,低级工具还支持创建包文件,这是本书范围之外的活动。

在下面的讨论中,术语 package_name 是指包的实际名称(actual name),而不是术语 package_file ,后者是包含包的文件的名称。此外,在执行任何包操作之前,需要查询包存储库,以便同步其数据库的本地副本。Red Hat的 dnf 程序会自动执行此操作,如果自上次更新以来已经过去了太多时间,则会更新本地数据库。另一方面,Debian的 apt 程序必须使用 update 命令运行,才能显式更新本地数据库。这需要经常进行。在下面的示例中, apt-update 命令是在任何操作之前完成的,但在现实生活中,为了保持安全,只需要每隔几个小时执行一次。

由于涉及在系统基础上安装或删除软件的操作是一项管理任务,因此无论使用何种包管理工具,都需要超级用户权限。

在存储库中查找包

使用高级工具搜索存储库元数据,可以根据其名称或描述定位包(见下表)。

风格命令
Debianapt update; apt search search_string
Red Hatdnf search search_string

例如,要在 dnf 存储库中搜索 emacs 文本编辑器,我们可以使用以下命令:

从存储库安装包

高级工具允许从存储库下载包,并以完全依赖性解决方案进行安装(见下表)。

风格命令
Debianapt update; apt install package_name
Red Hatdnf install package_name

例如,要在Debian系统上从 apt 存储库安装emacs文本编辑器,我们可以使用以下命令:

从包文件安装包

如果包文件是从存储库以外的源下载的,则可以使用低级工具直接安装(尽管没有依赖解析)(见下表)。

风格命令
Debiandpkg -i package_file
Red Hatrpm -i package_file

例如,如果 emacs-22.1-7.fc7-i386.rpm 包文件是从非存储库站点下载的,则将按以下方式安装:

注意:由于此技术使用低级 rpm 程序执行安装,因此不会执行依赖关系解析。如果 rpm 发现缺少依赖关系, rpm 将退出并出错。

删除包

可以使用高级或低级工具卸载软件包。高级工具如下表所示:

风格命令
Debianapt remove package_name
Red Hatdnf erase package_name

例如,要从Debian风格的系统中卸载 emacs 包,我们可以使用以下命令:

从存储库更新包

最常见的包管理任务是使系统保持最新版本的包。高级工具可以在一个步骤中执行这一重要任务(见下表)。

风格命令
Debianapt update; apt upgrade
Red Hatdnf update

例如,要将所有可用更新应用于Debian风格系统上已安装的软件包,我们可以使用以下命令:

从包文件升级包

如果从非存储库源下载了软件包的更新版本,则可以安装该版本,以替换之前的版本(见下表)。

风格命令
Debiandpkg -i package_file
Red Hatrpm -U package_file

例如,要在Red Hat系统上将现有的 emacs 安装更新到包文件 emacs-22.1-7.fc7-i386.rpm 中包含的版本,我们可以使用以下命令:

注意: dpkg 没有升级软件包的特定选项,也没有像 rpm 那样安装软件包的选项。

列出已安装的软件包

下表列出了我们可以用来显示系统上安装的所有软件包列表的命令:

风格命令
Debiandpkg -l
Red Hatrpm -qa

确定是否安装了程序包

下表列出了我们可以用来显示是否安装了指定包的低级工具:

风格命令
Debiandpkg -s package_name
Red Hatrpm -q package_name

例如,要确定 emacs 包是否安装在Debian风格的系统上,我们可以使用以下命令:

--status-s 的完整形态。】

显示有关已安装包的信息

如果已知已安装包的名称,我们可以使用下表中的命令显示包的描述:

风格命令
Debianapt show package_name
Red Hatdnf info package_name

例如,要查看Debian风格系统上 emacs 包的描述,我们可以使用以下命令:

查找哪个软件包安装了文件

要确定哪个包负责安装特定文件,我们可以使用下表中的命令:

风格命令
Debiandpkg -S file_name
Red Hatrpm -qf file_name

例如,要查看Red Hat系统上安装了 /usr/bin/vim 文件的软件包,我们可以使用以下方法:

独立于分发的包格式

在过去的几年里,发行版供应商推出了与特定Linux发行版无关的通用包格式。其中包括Snaps(由Canonical开发和推广)、Flatpaks(由Red Hat率先推出,但现在广泛使用)和AppImages。虽然它们的工作方式略有不同,但它们的目标是将应用程序及其所有依赖项捆绑在一起并安装在一个单独的部分中。这不是一个全新的想法。在Linux的早期(想想20世纪90年代末),有一种称为静态链接的技术,它将应用程序及其所需的库组合成一个大型二进制文件。

这种包装方法有一些好处。首先是减少分发应用程序所需的工作量。该应用程序是一次性构建的,可以安装在任何系统上,而不是定制应用程序以与发行版基础系统中的库和其他支持文件一起使用。其中一些格式还可以在容器化沙箱中运行应用程序,以提供额外的安全性。

但也有一些严重的缺点。以这种方式打包的应用程序很大。有时真的很大。这有两个影响。首先,它们需要大量的磁盘空间来存储。其次,它们的大尺寸会使它们的加载速度非常慢。在现代超高速硬件上,这可能不是什么大问题,但在旧机器上,这是一个真正的问题。下一个技术问题与分销集成有关。由于这些应用程序带来了所有的东西,因此它们没有利用底层分发的设施。有时,容器化应用程序无法访问最佳性能所需的系统资源。

然后是哲学问题。也许这些一体化应用程序包的最大受益者是专有软件供应商。他们可以构建一个Linux版本,每个发行版都可以使用它。不需要为不同的发行版定制他们的应用程序。

用户并没有强烈要求这些打包格式,而且它们对增强开源社区几乎没有什么作用,因此在各种性能问题得到解决之前,不建议使用这些格式。

总结

在接下来的章节中,我们将探索涵盖广泛应用领域的许多不同程序。虽然这些程序中的大多数通常是默认安装的,但如果没有提供必要的程序,我们可能需要安装其他软件包。凭借我们对包管理的新知识(和欣赏,appreciation),我们应该可以轻松安装和管理所需的程序。

Linux软件安装神话

从其他平台迁移的人有时会成为这样一种神话的受害者,即软件在Linux下难以安装,不同发行版使用的各种打包方案是一种障碍。好吧,这是一个障碍,但只适用于希望分发其秘密软件的纯二进制版本的专有软件供应商。

Linux软件生态系统基于开源代码的理念。如果程序开发人员发布了程序的源代码,那么与发行版关联的人很可能会打包该程序并将其包含在他们的存储库中。这种方法确保了程序很好地集成到分发中,并为用户提供了软件“一站式购物”的便利,而不必搜索每个程序的网站。最近,主要的专有平台供应商已经开始构建模仿这一想法的应用程序商店。

设备驱动程序的处理方式大致相同,只是它们不再是发行版存储库中的单独项目,而是成为Linux内核的一部分。一般来说,Linux中没有“驱动盘”这样的东西。内核要么支持某个设备,要么不支持,Linux内核支持很多设备。事实上,比Windows多得多。当然,如果您需要的特定设备不受支持,这并不能带来安慰。当这种情况发生时,你需要看看原因。缺乏驱动支持通常是由以下三种原因之一引起的:

  1. 设备太新了。 由于许多硬件供应商并不积极支持Linux开发,因此编写内核驱动程序代码的责任落在了Linux社区的一名成员身上。这需要时间。
  2. 这个装置太奇特了。 并非所有发行版都包含所有可能的设备驱动程序。每个发行版都构建自己的内核,由于内核非常可配置(这使得在从手表到大型机的所有设备上运行Linux成为可能),它们可能忽略了特定的设备。通过查找和下载驱动程序的源代码,您(是的,您)可以自己编译和安装驱动程序。这个过程并不太困难,但相当复杂。我们将在后面的章节中讨论编译软件。
  3. 硬件供应商有所隐瞒。 它既没有发布Linux驱动程序的源代码,也没有发布技术文档供他人为其创建驱动程序。这意味着硬件供应商正试图对设备的编程接口保密。既然我们不想在电脑里安装秘密设备,你最好避免使用此类产品。