dpkg 命令详解:在 Debian/Ubuntu 上安装与管理软件包

在 Ubuntu 或 Debian 上使用 apt 安装软件时,包管理器会在后台悄悄调用 dpkg 来完成实际工作。dpkg 是底层工具,负责解包并安装 .deb 文件、维护软件包数据库,并处理卸载与清除。当你手头有一个不在仓库中的本地 .deb 文件、需要查询某个软件包安装了哪些文件,或想找出系统中某个文件属于哪个软件包时,直接掌握 dpkg 的用法非常有用。

语法

dpkg [OPTIONS] COMMAND [ARGUMENTS]

安装、卸载、清除和配置操作需要 sudo 权限,因为它们会修改系统目录和软件包数据库。而查询类命令,如 dpkg -l、dpkg -L、dpkg -S 和 dpkg -s,通常无需 root 权限即可运行。

开始前无需安装任何东西。dpkg 在每个基于 Debian 的发行版中都标记为 Essential: yes 且 Priority: required,这意味着它随基础系统一同提供,且 apt 不允许你卸载它。如果下面的命令提示找不到,你几乎肯定使用的是采用其他包管理器(如 rpm 或 pacman)的发行版。

安装软件包

要安装本地的 .deb 文件:

sudo dpkg -i package.deb

dpkg 解包归档、运行维护者脚本,并将软件包登记到数据库中。如果软件包存在未满足的依赖,安装会在配置完成前停止,下一节将介绍如何处理。

当多个文件相互依赖时,可一次性传入多个文件,因为 dpkg 会先全部解包,再统一配置:

sudo dpkg -i *.deb

若只想解包而不运行配置步骤,可使用 sudo dpkg --unpack myapp.deb,之后再使用 sudo dpkg --configure myapp 配置。

对于大多数本地 .deb 安装,apt install ./package.deb 更方便,因为它能在同一步骤中解析依赖。当你确实需要底层包操作时,才使用 dpkg -i。

解决依赖错误

dpkg 只安装你交给它的那个文件。它不会查看仓库,也不会下载任何东西,因此存在未满足依赖的软件包会中途停止:

dpkg: dependency problems prevent configuration of myapp:
 myapp depends on libfoo1 (>= 1.2.0); however:
  Package libfoo1 is not installed.

dpkg: error processing package myapp (--install):
 dependency problems - leaving unconfigured
Errors were encountered while processing:
 myapp

请仔细阅读,因为软件包并未被移除。文件已解包、软件包已登记,但配置步骤从未运行。在你完成之前,apt 会拒绝处理任何其他事务。

解决方法是让 apt 补上 dpkg 无法提供的部分:

sudo apt install -f

apt 读取未配置的软件包,从你的仓库拉取缺失的依赖,然后重新运行失败的那一步配置。sudo apt --fix-broken install 是同一命令的完整写法。

你也可以在最初就通过 apt 安装该文件,从而在任何解包操作之前先解析依赖:

sudo apt install ./myapp.deb

./ 前缀很重要。没有它,apt 会把 myapp.deb 当作要在仓库中查找的软件包名。关于修复软件包状态的更多内容,请参阅 APT 与 dpkg 锁错误 指南。

卸载软件包

要卸载软件包但保留其配置文件:

sudo dpkg -r package-name

要同时卸载软件包并删除其配置文件(彻底清除):

sudo dpkg -P package-name

当你想要干净地移除且不留任何配置残留,或计划以全新配置重新安装时,使用 -P。这些命令对应的 apt 写法,请参阅 在 Ubuntu 上卸载软件包 指南。

重新安装软件包

当某个二进制文件被意外删除、配置文件被改坏,或软件包看起来已损坏时,重新安装很有用。dpkg 没有专门的重装标志,因为它并不需要。将一个已安装软件包指向 -i,会把它再次解包到现有文件之上:

sudo dpkg -i myapp.deb

当你磁盘上仍保留着 .deb 时,这种方式有效。对于来自仓库的软件包,可让 apt 获取相同版本并交给 dpkg:

sudo apt install --reinstall nginx

这两条命令默认都不会恢复被删除的、由软件包管理的配置文件。dpkg 将缺失的文件视为有意为之,并保留其缺失状态。要恢复 /etc/nginx/nginx.conf,需重新安装拥有它的 nginx-common 软件包,并加上 confmiss 强制选项:

sudo apt install --reinstall -o Dpkg::Options::
=
"--force-confmiss"
 nginx-common

列出已安装软件包

要列出记录在 dpkg 状态数据库中的软件包及其版本和状态:

dpkg -l

输出很宽。每个软件包行以三列状态开头:期望操作、当前软件包状态、错误状态。列表中可能包含带有残留配置文件的已卸载软件包,以及处于不完整状态的软件包,而不仅仅是完全安装的软件包。正常的已安装状态显示为 ii,其后依次是软件包名、版本、架构和描述:

Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version              Architecture Description
+++-==============-====================-============-=================================
ii  curl           8.5.0-2ubuntu10.13   amd64        command line tool for transferring data
ii  nginx          1.24.0-2ubuntu7.18   amd64        small, powerful, scalable web/proxy server

第一个 i 表示软件包被选为安装,第二个 i 表示它已安装并配置完成。按名称过滤以缩小输出:

dpkg -l 
'nginx*'
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version              Architecture Description
+++-==============-====================-============-=================================
ii  nginx          1.24.0-2ubuntu7.18   amd64        small, powerful, scalable web/proxy server
ii  nginx-common   1.24.0-2ubuntu7.18   all          small, powerful, scalable web/proxy server - common files

更多过滤、排序和导出该列表的方法,请参阅 在 Debian 上列出已安装软件包 指南。

列出软件包安装的文件

要查看某个软件包在系统中安装的所有文件:

dpkg -L nginx
/.
/usr
/usr/sbin
/usr/sbin/nginx
/usr/share
/usr/share/doc
/usr/share/doc/nginx
/usr/share/doc/nginx/changelog.Debian.gz
/usr/share/doc/nginx/copyright
/usr/share/man
/usr/share/man/man8
/usr/share/man/man8/nginx.8.gz

注意该列表包含二进制文件、更新日志和手册页,但不含配置文件。Debian 软件包经常拆分,nginx 软件包只提供服务器本身,配置则位于单独的软件包中。下面的过滤展示了 nginx-common 中的几个主要配置文件:

dpkg -L nginx-common 
|
 grep -E 
'^/etc/nginx/(fastcgi\.conf|mime\.types|nginx\.conf|sites-available/default)$'
/etc/nginx/fastcgi.conf
/etc/nginx/mime.types
/etc/nginx/nginx.conf
/etc/nginx/sites-available/default

这种拆分正是值得使用 dpkg -L 的原因。当你预期某个文件而软件包未列出它时,通常是一个 -common、-data 或 -doc 配套软件包拥有它。

查找文件所属的软件包

要识别安装某个特定文件的软件包:

dpkg -S /usr/sbin/nginx
nginx: /usr/sbin/nginx

你也可以按模式搜索:

dpkg -S 
'*/bin/curl'
curl: /usr/bin/curl

显示软件包详情

要打印已安装软件的完整元数据,包括版本、依赖和描述:

dpkg -s nginx
Package: nginx
Status: install ok installed
Priority: optional
Section: httpd
Installed-Size: 1323
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Version: 1.24.0-2ubuntu7.18
Depends: libc6 (>= 2.34), libssl3t64 (>= 3.0.0), nginx-common (= 1.24.0-2ubuntu7.18)
...

Status 行是首先要读取的字段。install ok installed 表示该软件包已完全安装并配置完成。你卸载但未清除的软件包会显示 deinstall ok config-files,这表示配置文件仍在磁盘上。Installed-Size 以千字节为单位报告。

在不安装的情况下检查 .deb 文件

要在安装前读取 .deb 文件的元数据:

dpkg --info package.deb
 new Debian package, version 2.0.
 size 1234567 bytes: control archive=2048 bytes.
     ...
 Package: myapp
 Version: 2.1.0
 Architecture: amd64
 ...

要列出该软件包将安装的文件,而无需真正安装它:

dpkg --contents package.deb

在不安装的情况下解包

要将 .deb 文件的内容解包到某个目录以供检查:

dpkg -x package.deb /tmp/extracted

目录结构映射了文件在真实系统上的安装位置。

导出与恢复软件包选择状态

要导出 dpkg 的软件包选择状态(便于复制一套系统):

dpkg --get-selections > installed-packages.txt

该文件可包含 install、hold、deinstall 和 purge 状态。在另一台机器上恢复之前,需先将 APT 的软件包元数据复制到 dpkg 的可用软件包数据库中,这样 --set-selections 才能识别尚未安装的软件包:

apt-cache dumpavail 
|
 sudo dpkg --merge-avail

sudo dpkg --set-selections < installed-packages.txt

在应用前预览将要发生的软件包变更:

sudo apt-get --simulate dselect-upgrade

如果提议的变更正确,应用它们:

sudo apt-get dselect-upgrade

重新配置已安装的软件包

某些软件包在安装时会运行交互式设置。要再次运行该设置:

sudo dpkg-reconfigure package-name

这通常用于重新配置 tzdata(时区变更)、keyboard-configuration 或 locales。

修复损坏的软件包状态

在修复之前,先运行审计以查看哪些软件包处于异常状态:

dpkg -C
The following packages are only half configured, probably due to problems
configuring them the first time. The configuration should be retried using
dpkg --configure <package> or the configure menu option in dselect:
 myapp   My application

没有输出表示一切正常。

如果系统更新或手动操作导致软件包处于半安装或半配置状态,运行:

sudo dpkg --configure -a

这会处理所有挂起的软件包配置步骤。如果仍有依赖问题,接着运行 sudo apt install -f。

故障排查

dpkg 报告依赖问题:dpkg 会安装你提供的软件包文件,但不会下载缺失的依赖。运行 sudo apt install -f 安装所需软件包并完成挂起的配置。

软件包操作被中断:如果更新或安装在配置完成前停止,运行 sudo dpkg --configure -a。这会恢复挂起的软件包配置脚本。

dpkg 报告错误退出状态 1:失败的是维护者脚本,而非 dpkg 本身。错误上方的那一行会指出软件包和脚本名称,通常是 post-installation script subprocess returned error exit status 1。运行 sudo dpkg --configure -a 重试,并查看失败正上方的输出来找出真正原因——通常是某个服务无法启动或依赖缺失。

dpkg 无法获取锁:另一个包操作正持有数据库锁。请等待它完成,而不是删除锁文件。请参阅 修复 APT 与 dpkg 锁错误 指南。

dpkg 找不到软件包:请使用已安装的软件包名,而非 .deb 文件名。运行 dpkg -l 'pattern*' 查找匹配的已安装软件包,然后将该软件包名用于 dpkg -L、dpkg -s 或 sudo dpkg -r 等命令。

快速参考

如需可打印的快速参考,请参阅 dpkg 速查表。

命令说明
dpkg -i pkg.deb安装本地 .deb 文件
dpkg -r package卸载软件包(保留配置)
dpkg -P package彻底清除软件包及其配置
dpkg --unpack pkg.deb仅解包不配置
dpkg -l列出软件包状态记录
dpkg -l 'pattern*'过滤软件包状态记录
dpkg -L package列出软件包安装的文件
dpkg -S /path/to/file查找文件所属的软件包
dpkg -s package显示软件包状态与详情
dpkg --info pkg.deb检查 .deb 文件
dpkg --contents pkg.deb列出 .deb 中的文件
dpkg -x pkg.deb /dir不安装解包 .deb
dpkg --get-selections导出软件包选择状态
dpkg-reconfigure package重新运行软件包配置
dpkg -C审计损坏状态的软件包
dpkg --configure -a修复不完整的安装

常见问题

dpkg 与 apt 有什么区别?dpkg 处理本地的 .deb 文件和本地软件包数据库。它不了解仓库,也不会解析依赖。apt 是前端,它与仓库通信、计算依赖树、下载所需内容,然后调用 dpkg 完成实际安装。

我需要先安装 dpkg 吗?不需要。dpkg 是每个基于 Debian 的发行版中的基础软件包,因此它已在系统上,且 apt 拒绝卸载它。运行 dpkg --version 确认你拥有的版本。

dpkg -i 是升级软件包还是安装第二份副本?它会就地替换已安装的版本。Debian 打包规则每个架构只允许一个软件包版本,因此 dpkg 将提供的版本解包到现有版本之上并运行软件包维护者脚本。如果文件包含较旧版本,dpkg 会打印降级警告并默认继续,但它不会检查降级是否会破坏另一个软件包的依赖。APT 也能在显式指定旧版本时降级软件包,例如 sudo apt install package-name=version。

dpkg -l 输出中的 ii 是什么意思?第一个字母是你要求的(期望)状态,第二个字母是软件包的实际状态,因此 ii 表示你要求安装它,且它已安装并配置完成。rc 是另一个常见组合:软件包已卸载,但其配置文件仍在磁盘上。第二个字母为大写(如 iU 或 iF)表示软件包已解包或半配置,需要运行 sudo dpkg --configure -a。

结论

dpkg 是基于 Debian 系统上软件包管理的基础。对于日常从仓库安装和更新,apt 是更好的工具,因为它会自动解析依赖。当你需要安装磁盘上的 .deb 文件、审计某个软件包安装了什么,或诊断损坏的软件包状态时,直接动用 dpkg。