dpkg 命令详解与参数实测(Ubuntu 22.04)
dpkg 命令详解:在 Ubuntu 22.04(dpkg 1.21.1)环境逐参数实测 -i/-r/-P 安装删除、-l 状态码 ii/rc/un 逐列解读、-L/-S/-s 查询、--unpack/--configure 分步修复、--get-selections/--set-selections、-c/--info 包内审阅、-C 审计与 --verify 校验,并以实测证明 dpkg 无依赖解析及 dpkg 与 apt 的分工。
dpkg 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 dpkg 的每一个常用参数——-i/-r/-P 安装删除、-l/-L/-S/-s 状态查询、--unpack/--configure 分步控制、--get-selections/--set-selections 选中状态、-c/--info/-f 包内审阅、-C 审计与 --verify 校验,全部命令与回显已在 Ubuntu 22.04(dpkg 1.21.1)实测通过。
一、环境信息
本篇所有命令均在以下环境中逐条真实执行,回显为实际输出(非编造):
- 操作系统:Ubuntu 22.04.5 LTS(x86_64),内核
6.8.0-138-generic - dpkg 版本:程序自报
1.21.1 (amd64),软件包版本1.21.1ubuntu2.6 - apt 版本:
apt 2.4.14 (amd64)(配合 install -f 修依赖时使用) - 状态数据库:
/var/lib/dpkg/status(包状态)、/var/lib/dpkg/available(可选库) - 测试数据包:
sl 5.02-1(13K,无 conffiles)、cowsay 3.03+dfsg2-8(依赖 libtext-charwidth-perl)、plocate 1.1.15-1ubuntu2(含 conffile /etc/updatedb.conf) - 全部 .deb 通过
apt-get download从官方源获取,路径/root/*.deb
二、命令概览
2.1 语法与测试数据
dpkg 是 Debian 系的底层包管理器,直接操作 .deb 文件与状态数据库,不联网、不解析依赖:
dpkg [<选项>...] <命令>
dpkg -i <.deb 文件> # 安装本地包
dpkg -r <包名> # 删除(保留配置文件)
dpkg -P <包名> # 清除(连配置文件一起删)
dpkg -l [模式] # 列出包及状态码
dpkg -L <包名> # 列出包安装的所有文件
dpkg -S <文件路径|模式> # 反查文件属于哪个包
dpkg -s <包名> # 显示包状态详情
常用命令一览:
| 命令 | 作用 | 本文实测 |
|---|---|---|
-i / --install | 安装本地 .deb | 是(3.2、3.3 节) |
--unpack / --configure | 解包与配置分步执行 | 是(3.4 节) |
-r / --remove | 删除包,保留 conffiles | 是(3.5 节) |
-P / --purge | 清除包及 conffiles | 是(3.6 节) |
-l / --list | 列表与状态码 | 是(3.1 节) |
-L / --listfiles | 包文件清单 | 是(3.7 节) |
-S / --search | 文件反查包 | 是(3.8 节) |
-s / --status | 包状态详情 | 是(3.9 节) |
-c / --info(经 dpkg-deb) | 审阅未安装的 .deb | 是(3.10 节) |
--get-selections / --set-selections | 读写选中状态 | 是(3.11 节) |
-C / --audit | 审计损坏/半成品包 | 是(3.12 节) |
-V / --verify | 校验已装文件完整性 | 是(3.12 节) |
💡 技术拓展:dpkg 与 apt 是「引擎与导航」的分工关系——
工具 定位 依赖解析 典型用途 dpkg 底层引擎:直接解包 .deb、维护状态库 无——依赖缺失时报错并把包留在未配置状态 安装本地 .deb、查文件归属、状态审计 apt / apt-get 前端:面向软件源,读 dpkg 状态库做决策 有——自动算出依赖闭包并下载补齐 在线安装/升级/批量依赖处理 本文 3.3 节用实测证明了「dpkg 无依赖解析」:
dpkg -i缺依赖直接 rc=1 留下 iU 状态,随后apt-get install -f才补齐依赖并完成配置。两者是互补而非替代。
测试数据包说明:sl(火车动画小游戏,装在 /usr/games/sl)体积小、无 conffiles,适合演示安装/删除;cowsay(会说话的牛)依赖 libtext-charwidth-perl,用于构造缺依赖场景;plocate(文件定位工具)自带 conffile /etc/updatedb.conf,用于演示 ii→rc→清除 的完整状态迁移。
2.2 --help 全量输出(逐行照抄)
$ dpkg --help 2>&1
Usage: dpkg [<option>...] <command>
Commands:
-i|--install <.deb file name>... | -R|--recursive <directory>...
--unpack <.deb file name>... | -R|--recursive <directory>...
-A|--record-avail <.deb file name>... | -R|--recursive <directory>...
--configure <package>... | -a|--pending
--triggers-only <package>... | -a|--pending
-r|--remove <package>... | -a|--pending
-P|--purge <package>... | -a|--pending
-V|--verify [<package>...] Verify the integrity of package(s).
--get-selections [<pattern>...] Get list of selections to stdout.
--set-selections Set package selections from stdin.
--clear-selections Deselect every non-essential package.
--update-avail [<Packages-file>] Replace available packages info.
--merge-avail [<Packages-file>] Merge with info from file.
--clear-avail Erase existing available info.
--forget-old-unavail Forget uninstalled unavailable pkgs.
-s|--status [<package>...] Display package status details.
-p|--print-avail [<package>...] Display available version details.
-L|--listfiles <package>... List files 'owned' by package(s).
-l|--list [<pattern>...] List packages concisely.
-S|--search <pattern>... Find package(s) owning file(s).
-C|--audit [<package>...] Check for broken package(s).
--yet-to-unpack Print packages selected for installation.
--predep-package Print pre-dependencies to unpack.
--add-architecture <arch> Add <arch> to the list of architectures.
--remove-architecture <arch> Remove <arch> from the list of architectures.
--print-architecture Print dpkg architecture.
--print-foreign-architectures Print allowed foreign architectures.
--assert-help Show help on assertions.
--assert-<feature> Assert support for the specified feature.
--validate-<thing> <string> Validate a <thing>'s <string>.
--compare-versions <a> <op> <b> Compare version numbers - see below.
--force-help Show help on forcing.
-Dh|--debug=help Show help on debugging.
-?, --help Show this help message.
--version Show the version.
Validatable things: pkgname, archname, trigname, version.
Use dpkg with -b, --build, -c, --contents, -e, --control, -I, --info,
-f, --field, -x, --extract, -X, --vextract, --ctrl-tarfile, --fsys-tarfile
on archives (type dpkg-deb --help).
Options:
--admindir=<directory> Use <directory> instead of /var/lib/dpkg.
--root=<directory> Install on a different root directory.
--instdir=<directory> Change installation dir without changing admin dir.
--pre-invoke=<command> Set a pre-invoke hook.
--post-invoke=<command> Set a post-invoke hook.
--path-exclude=<pattern> Do not install paths which match a shell pattern.
--path-include=<pattern> Re-include a pattern after a previous exclusion.
-O|--selected-only Skip packages not selected for install/upgrade.
-E|--skip-same-version Skip packages whose same version is installed.
-G|--refuse-downgrade Skip packages with earlier version than installed.
-B|--auto-deconfigure Install even if it would break some other package.
--[no-]triggers Skip or force consequential trigger processing.
--verify-format=<format> Verify output format (supported: 'rpm').
--no-pager Disables the use of any pager.
--no-debsig Do not try to verify package signatures.
--no-act|--dry-run|--simulate
Just say what we would do - don't do it.
-D|--debug=<octal> Enable debugging (see -Dhelp or --debug=help).
--status-fd <n> Send status change updates to file descriptor <n>.
--status-logger=<command> Send status change updates to <command>'s stdin.
--log=<filename> Log status changes and actions to <filename>.
--ignore-depends=<package>[,...]
Ignore dependencies involving <package>.
--force-<thing>[,...] Override problems (see --force-help).
--no-force-<thing>[,...] Stop when problems encountered.
--refuse-<thing>[,...] Ditto.
--abort-after <n> Abort after encountering <n> errors.
--robot Use machine-readable output on some commands.
Comparison operators for --compare-versions are:
lt le eq ne ge gt (treat empty version as earlier than any version);
lt-nl le-nl ge-nl gt-nl (treat empty version as later than any version);
< << <= = >= >> > (only for compatibility with control file syntax).
Use 'apt' or 'aptitude' for user-friendly package management.
注意帮助末尾那句官方提示:Use 'apt' or 'aptitude' for user-friendly package management.——dpkg 定位就是底层工具,日常在线安装交给 apt。对 .deb 文件本身的操作(-c/--info/-f 等)由同族的 dpkg-deb 提供。
2.3 版本信息
$ dpkg --version
Debian 'dpkg' package management program version 1.21.1 (amd64).
This is free software; see the GNU General Public License version 2 or
later for copying conditions. There is NO warranty.
$ dpkg -l dpkg | tail -1
ii dpkg 1.21.1ubuntu2.6 amd64 Debian package management system
程序自报版本 1.21.1(上游版本号),软件包版本为 1.21.1ubuntu2.6(含 Ubuntu 补丁的后缀)。查包版本用 dpkg -l dpkg,查程序版本用 dpkg --version,两者口径不同、各有用途。
三、参数逐项实测
3.1 -l:列表与状态码(重点:ii/rc/un 逐列解读)
dpkg -l 是状态巡检的入口。输出开头的 3 行图例就是状态码的官方解释:
$ dpkg -l | head -8
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 adduser 3.118ubuntu5 all add and remove users and groups
ii apparmor 3.0.4-2ubuntu2.5 amd64 user-space parser utility for AppArmor
ii apt 2.4.14 amd64 commandline package manager
每个包行前三列字符逐一解读(后跟错误位,大写=异常):
| 列 | 含义 | 取值 |
|---|---|---|
| 第 1 列 Desired | 期望动作 | i 安装、r 删除、p 清除、h 锁定、u 未知 |
| 第 2 列 Status | 当前状态 | i 已安装、c 仅剩配置文件、n 未安装、u 已解包未配置、f 半配置、h 半安装、w/t 触发器等待/挂起 |
| 第 3 列 Err | 错误标志 | 空格正常、R 需要重装 |
本文实测出现过的组合及含义:ii(期望安装、已安装,正常态)、rc(期望删除、只剩配置文件)、iU(期望安装、解包未配置)、in(期望安装、尚未安装)、un(无选中、未安装)。查询单个包同样带图例头:
$ dpkg -l libc6
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 libc6:amd64 2.35-0ubuntu3.15 amd64 GNU C Library: Shared libraries
$ dpkg -l not-exist-pkg 2>&1; echo rc=$?
dpkg-query: no packages found matching not-exist-pkg
rc=1
💡 要点:
dpkg -l 包名查不到时退出码为 1 而非 100——dpkg 查询类错误(dpkg-query)与操作类错误(rc=100)返回码不同,写脚本时注意区分。
3.2 -i:安装本地 .deb(依赖满足直接成功)
先用 apt-get download 取一个真实 .deb,再离线安装:
$ cd /root && apt-get download sl 2>&1 | tail -1
W: Download is performed unsandboxed as root as file '/root/sl_5.02-1_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
$ ls -lh /root/sl_*.deb
-rw-r--r-- 1 root root 13K Feb 2 2019 /root/sl_5.02-1_amd64.deb
$ dpkg -i /root/sl_*.deb; echo rc=$?
Selecting previously unselected package sl.
(Reading database ... 26317 files and directories currently installed.)
Preparing to unpack /root/sl_5.02-1_amd64.deb ...
Unpacking sl (5.02-1) ...
Setting up sl (5.02-1) ...
rc=0
$ dpkg -l sl | tail -1
ii sl 5.02-1 amd64 Correct you if you type `sl' by mistake
流程四步:Selecting(选中)→ Unpacking(解包)→ Setting up(配置)→ rc=0。下载时的 W: Download is performed unsandboxed as root 是以 root 直接下载的提示(apt 希望用 _apt 用户沙箱下载),不影响结果,属常见现象。
sl 的依赖(libc6/libncurses6/libtinfo6)系统本就满足,所以 -i 一步到位。若运行它,由于 sl 是全屏动画程序、需要终端环境,无终端时如实报错:
💡 要点:
dpkg -i是纯本地安装器——只认命令行给到的 .deb 文件,不会去仓库查找缺失依赖(3.3 节实证)。它适合「已备齐全部 .deb 的离线场景」;联网机器装第三方 .deb 更省心的写法是apt install ./xxx.deb,让 apt 顺手补依赖。开头的W: Download is performed unsandboxed as root是以 root 身份执行apt-get download的沙箱提示,不影响安装结果。
$ /usr/games/sl 2>&1 | head -4
Error opening terminal: unknown.
3.3 -i 缺依赖:dependency problems(rc=1),证明 dpkg 无依赖解析
cowsay 依赖 libtext-charwidth-perl,先卸掉它再 dpkg -i,观察真实失败形态:
$ dpkg -P sl >/dev/null 2>&1; echo sl-purged
sl-purged
$ cd /root && apt-get download cowsay 2>&1 | tail -1
W: Download is performed unsandboxed as root as file '/root/cowsay_3.03+dfsg2-8_all.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
$ dpkg -i /root/cowsay_*.deb; echo rc=$?
Selecting previously unselected package cowsay.
(Reading database ... 26317 files and directories currently installed.)
Preparing to unpack .../cowsay_3.03+dfsg2-8_all.deb ...
Unpacking cowsay (3.03+dfsg2-8) ...
dpkg: dependency problems prevent configuration of cowsay:
cowsay depends on libtext-charwidth-perl; however:
Package libtext-charwidth-perl is not installed.
dpkg: error processing package cowsay (--install):
dependency problems - leaving unconfigured
Errors were encountered while processing:
cowsay
rc=1
$ dpkg -l cowsay | tail -1
iU cowsay 3.03+dfsg2-8 all configurable talking cow
$ dpkg -C; echo rc=$?
The following packages have been unpacked but not yet configured.
They must be configured using dpkg --configure or the configure
menu option in dselect for them to work:
cowsay configurable talking cow
rc=0
失败形态三要素:报错段 dependency problems prevent configuration、退出码 rc=1、状态停在 iU(解包未配置)。dpkg -C 审计也能立刻发现这个半成品。此时 dpkg 不会自己去装 libtext-charwidth-perl——补依赖交给 apt 的 -f(fix-broken):
$ DEBIAN_FRONTEND=noninteractive apt-get install -f -y -o Dpkg::Use-Pty=0 2>&1 | tail -6
Selecting previously unselected package libtext-charwidth-perl.
(Reading database ... 26377 files and directories currently installed.)
Preparing to unpack .../libtext-charwidth-perl_0.04-10build3_amd64.deb ...
Unpacking libtext-charwidth-perl (0.04-10build3) ...
Setting up libtext-charwidth-perl (0.04-10build3) ...
Setting up cowsay (3.03+dfsg2-8) ...
$ dpkg -l cowsay | tail -1
ii cowsay 3.03+dfsg2-8 all configurable talking cow
$ /usr/games/cowsay dpkg works
____________
< dpkg works >
------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
apt-get install -f 补装缺失依赖并顺势把 cowsay 配置完成(iU → ii),程序可正常运行。这就是「dpkg 装包 + apt 修依赖」的标准组合拳。
💡 要点:这套二段式是 Ubuntu 离线/半离线装包的固定套路:dpkg 负责把 .deb 落盘解包,apt 负责从仓库补齐依赖并完成配置。脚本化时写成
dpkg -i xxx.deb || apt-get install -f -y,并把dpkg -C(审计半成品)接在后面做验证,能覆盖绝大多数离线安装失败形态。
3.4 --unpack 与 --configure:分步安装,--configure -a 修复半配置
把安装拆成两步,观察状态变化:
$ dpkg --unpack /root/sl_*.deb; echo rc=$?
Selecting previously unselected package sl.
(Reading database ... 26317 files and directories currently installed.)
Preparing to unpack /root/sl_5.02-1_amd64.deb ...
Unpacking sl (5.02-1) ...
rc=0
$ dpkg -l sl | tail -1
iU sl 5.02-1 amd64 Correct you if you type `sl' by mistake
$ dpkg --configure sl; echo rc=$?
Setting up sl (5.02-1) ...
rc=0
$ dpkg -l sl | tail -1
ii sl 5.02-1 amd64 Correct you if you type `sl' by mistake
--unpack 只解文件不配置(iU),--configure 包名 补上配置(ii)。--configure -a 则扫描所有未配置/半配置的包逐一修复,健康系统上无事可做、静默返回 rc=0:
$ dpkg --configure -a; echo rc=$?
rc=0
💡 要点:apt 升级中途断电/被杀后,最常见的修复口诀就是「先
dpkg --configure -a,再apt-get install -f」——前者把解包未配置的收尾,后者补齐缺失依赖。
3.5 -r:删除包(ii → rc)
用带 conffile 的 plocate 演示。删除前确认 /etc/updatedb.conf 存在:
$ DEBIAN_FRONTEND=noninteractive apt-get install -y -qq -o Dpkg::Use-Pty=0 plocate >/dev/null 2>&1; echo install_rc=$?
install_rc=0
$ dpkg -l plocate
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 plocate 1.1.15-1ubuntu2 amd64 much faster locate
$ ls -l /etc/updatedb.conf
-rw-r--r-- 1 root root 568 Feb 9 2022 /etc/updatedb.conf
$ dpkg -r plocate; echo rc=$?
(Reading database ... 26333 files and directories currently installed.)
Removing plocate (1.1.15-1ubuntu2) ...
rc=0
$ dpkg -l plocate
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
+++-==============-===============-============-=================================
rc plocate 1.1.15-1ubuntu2 amd64 much faster locate
$ ls -l /etc/updatedb.conf
-rw-r--r-- 1 root root 568 Feb 9 2022 /etc/updatedb.conf
验证闭环:状态从 ii 变 rc,而 conffile /etc/updatedb.conf 原样保留(568 字节未动)——-r 的语义就是「删程序、留配置」,方便下次重装沿用手工调过的配置。
💡 要点:
rc状态包是「已卸载但配置残留」的标记,巡检时用dpkg -l | awk '/^rc/{print $2}'列出,确认无用后可xargs dpkg -P批量清除。选-r还是-P的判断标准只有一个:这些 conffile 里有没有手工改动且将来还要用——有则-r,没有则-P。
3.6 -P:清除包(rc → 记录消失)
$ dpkg -P plocate; echo rc=$?
(Reading database ... 26320 files and directories currently installed.)
Purging configuration files for plocate (1.1.15-1ubuntu2) ...
rc=0
$ dpkg -l plocate 2>&1; echo rc=$?
dpkg-query: no packages found matching plocate
rc=1
-P 输出 Purging configuration files for plocate,随后记录从状态库中彻底消失(查询报 no packages found、rc=1)。对比 -r:无 conffiles 的包(如本文的 sl)在 -r 后记录也会直接消失,因为没有任何东西可留。
💡 要点:
-P不可逆——包记录从/var/lib/dpkg/status彻底移除,之后dpkg -s/-L都查不到任何痕迹。有「卸载审计」要求的服务器建议日常只用-r(保留 rc 记录作为卸载凭证),定期统一清理 rc 状态包。
3.7 -L:列出包安装的所有文件
$ dpkg -L sl | head -8
/.
/usr
/usr/games
/usr/games/sl
/usr/share
/usr/share/doc
/usr/share/doc/sl
/usr/share/doc/sl/README
💡 要点:
dpkg -L是「包 → 文件」方向,可执行文件在哪个目录(如 /usr/games)一眼可见;配合dpkg -S的「文件 → 包」方向形成互查闭环。
3.8 -S:文件反查属于哪个包
$ dpkg -S /usr/games/sl
sl: /usr/games/sl
$ dpkg -S /bin/ls
coreutils: /bin/ls
$ dpkg -S /etc/hostname 2>&1; echo rc=$?
dpkg-query: no path found matching pattern /etc/hostname
rc=1
/bin/ls 属于 coreutils;而 /etc/hostname 查不到——它由系统安装流程生成,不属于任何软件包,属正常现象。-S 在排查「这个二进制/配置是谁家的」时非常好用。
💡 要点:
dpkg -S的检索范围仅限已安装的包;要回答「仓库里哪个包能提供这个文件」(还没装的情况),需安装apt-file后用apt-file search 路径。排查陌生二进制来源时先用-S(零安装成本),查不到再上 apt-file。
3.9 -s:包状态详情
$ dpkg -s sl | head -12
Package: sl
Status: install ok installed
Priority: optional
Section: games
Installed-Size: 59
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Version: 5.02-1
Depends: libc6 (>= 2.2.5), libncurses6 (>= 6), libtinfo6 (>= 6)
Description: Correct you if you type `sl' by mistake
Sl is a program that can display animations aimed to correct you
if you type 'sl' by mistake.
第二行 Status: install ok installed 就是 -l 里 ii 的全拼(期望动作 ok 状态)。比 -l 更详细的还有 Version、Depends、Installed-Size 等字段,脚本解析建议用 dpkg-query -W -f 自定义格式。
💡 要点:
dpkg -s的输出面向人读,字段顺序与内容随包而变;脚本取单一字段务必改用dpkg-query -W -f='${Status} ${Version}\n' 包名,一行拿到结构化结果(如判断install ok installed),避免解析长文本的脆弱性。
3.10 -c / --info / dpkg-deb -f:审阅未安装的 .deb
不安装也能看包内容与元信息(对 .deb 的操作由 dpkg-deb 引擎承接):
$ dpkg -c /root/sl_*.deb | head -8
drwxr-xr-x root/root 0 2019-02-02 11:57 ./
drwxr-xr-x root/root 0 2019-02-02 11:57 ./usr/
drwxr-xr-x root/root 0 2019-02-02 11:57 ./usr/games/
-rwxr-xr-x root/root 26568 2019-02-02 11:57 ./usr/games/sl
drwxr-xr-x root/root 0 2019-02-02 11:57 ./usr/share/
drwxr-xr-x root/root 0 2019-02-02 11:57 ./usr/share/doc/
drwxr-xr-x root/root 0 2019-02-02 11:57 ./usr/share/doc/sl/
-rw-r--r-- root/root 360 2019-01-29 12:15 ./usr/share/doc/sl/README
dpkg-deb: error: tar subprocess was killed by signal (Broken pipe)
$ dpkg --info /root/sl_*.deb
new Debian package, version 2.0.
size 12708 bytes: control archive=960 bytes.
516 bytes, 14 lines control
1021 bytes, 16 lines md5sums
Package: sl
Version: 5.02-1
Architecture: amd64
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Markus Frosch <lazyfrosch@debian.org>
Installed-Size: 59
Depends: libc6 (>= 2.2.5), libncurses6 (>= 6), libtinfo6 (>= 6)
Section: games
Priority: optional
Homepage: https://github.com/mtoyoda/sl
Description: Correct you if you type `sl' by mistake
Sl is a program that can display animations aimed to correct you
if you type 'sl' by mistake.
SL stands for Steam Locomotive.
$ dpkg-deb -f /root/sl_*.deb Package Version Architecture Depends
Package: sl
Version: 5.02-1
Architecture: amd64
Depends: libc6 (>= 2.2.5), libncurses6 (>= 6), libtinfo6 (>= 6)
-c 列文件清单(权限/属主/大小),--info 展示 control 元信息与校验摘要,dpkg-deb -f 按字段名精确提取——脚本里提取单个字段(如 Depends)优先用第三种。注意 -c | head 结尾的 Broken pipe 报错是管道截断(head 只取 8 行)触发的 SIGPIPE,属正常现象,不影响结果;不想要这条报错可改用 dpkg-deb -c 包.deb > 文件 后再截取。
💡 要点:审计第三方 .deb 的标准三连——
--info看元信息与依赖声明 →-c看落盘路径清单(重点核对有没有往 /etc/systemd/system、/etc/cron.* 塞自启项)→ 确认无异常再-i。dpkg-deb -f 字段名是脚本提取单字段的唯一可靠方式(依赖名、版本号等),别用-c/--info的输出做文本解析。
3.11 --get-selections / --set-selections:读写选中状态
选中状态是比「是否安装」更底层的一层:即使包未装,也可以先「登记」期望动作(install/hold/deinstall/purge)。先看全量:
$ dpkg --get-selections | head -5
adduser install
apparmor install
apt install
base-files install
base-passwd install
$ dpkg --get-selections | wc -l
353
$ dpkg --get-selections bash
bash install
构造一条「未安装但已登记」的记录:--record-avail 把 .deb 元信息写入 available 库,随后 --set-selections 才能识别它:
$ dpkg --record-avail /root/sl_*.deb; echo rc=$?
Recorded info about sl from /root/sl_5.02-1_amd64.deb.
rc=0
$ echo 'sl install' | dpkg --set-selections; echo rc=$?
rc=0
$ dpkg --get-selections sl; echo rc=$?
sl install
rc=0
$ dpkg -l sl | tail -1
in sl <none> amd64 (no description available)
$ echo 'sl deinstall' | dpkg --set-selections; echo rc=$?
rc=0
$ dpkg -l sl | tail -1
un sl <none> amd64 (no description available)
验证闭环:登记 install 后状态行显示 in(期望安装、未安装),改登记 deinstall 后显示 un(无选中、未安装)。apt-mark 的 hold 本质就是把选中状态写成 hold——echo '包名 hold' | dpkg --set-selections 与 apt-mark hold 包名 等效,可用 dpkg --get-selections 包名 交叉验证(实测见 hold 相关章节)。
💡 要点:这组命令是 apt-mark hold/unhold 的底层实现——批量锁版的脚本写法是「echo 多行『包名 hold』 | dpkg --set-selections」一次灌入,比循环调 apt-mark 快得多。
in/un这类「登记未装」状态是 available 库残留的中间态,正常系统不应长期存在,巡检时见到可用dpkg --clear-avail清理。
3.12 -C:审计半成品,--verify:校验文件完整性
健康系统上两个命令都应静默通过:
$ dpkg -C; echo rc=$?
rc=0
$ dpkg --verify; echo rc=$?
rc=0
-C 输出为空表示没有未配置/半安装/损坏的包;--verify 对照每个包的 md5sums 清单校验已装文件,输出为空表示所有文件与安装时一致。3.3 节曾实测过 -C 报告 iU 半成品包的形态,两者对照即是完整的「审计 → 修复 → 复查」闭环。
💡 要点:两个命令的分工——
-C管「装好了没」(dpkg 状态机视角),--verify管「文件被动过没」(md5sums 基线视角)。批量安装脚本收尾跑-C做断言,安全巡检定时跑--verify抓配置篡改;两者都是「静默即健康」,写脚本时按非空输出报警处理即可。
3.13 技术拓展:dpkg 与 apt 家族的分工对比
Debian 系包管理命令不止 dpkg 一个,初学者常混淆「谁负责什么」。主流工具横向对比——
| 工具 | 层级 | 依赖解析 | 典型用途 |
|---|---|---|---|
| dpkg | 底层包引擎 | 无(3.3 节实证) | 装本地 .deb、查状态/文件清单、选中状态管理 |
| apt-get | 高层前端 | 有(自动补依赖) | 脚本化安装/升级,输出稳定、rc 约定清晰 |
| apt | 高层前端 | 有 | 交互式日常使用,进度条 + 精简输出(面向人) |
| apt-cache | 高层查询 | 不涉及(只读) | 离线检索包元信息(不碰网络,走本地缓存) |
| dpkg-deb | 底层工具 | 不涉及 | 审阅/解包/构建单个 .deb 文件 |
| aptitude | 另一套前端 | 有 | 交互式 TUI 与更智能的冲突解决(Ubuntu 默认未装) |
💡 关键差异一句话:dpkg 管「单个包的落地与状态」,apt 系管「依赖网络的求解」——两者是引擎与调度层的关系,不是竞争关系。本文以 dpkg 为主线实测其底层能力(状态码、选中状态、文件反查),依赖求解场景一律交回 apt 系处理(如 3.3 节的
apt-get install -f)。
四、实战示例
4.1 离线安装 .deb 及其依赖(一次 dpkg -i 多包)
场景:内网服务器拿不到软件源,先在有网机器 apt-get download 把主包和依赖全部下齐,拷贝过去一次装完:
$ cd /root && apt-get download cowsay libtext-charwidth-perl 2>&1 | tail -1
W: Download is performed unsandboxed as root as file '/root/libtext-charwidth-perl_0.04-10build3_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
$ ls -lh /root/cowsay_*.deb /root/libtext-charwidth-perl_*.deb
-rw-r--r-- 1 root root 19K May 12 2020 /root/cowsay_3.03+dfsg2-8_all.deb
-rw-r--r-- 1 root root 10K Feb 6 2022 /root/libtext-charwidth-perl_0.04-10build3_amd64.deb
$ dpkg -i /root/cowsay_*.deb /root/libtext-charwidth-perl_*.deb; echo rc=$?
Selecting previously unselected package cowsay.
(Reading database ... 26317 files and directories currently installed.)
Preparing to unpack .../cowsay_3.03+dfsg2-8_all.deb ...
Unpacking cowsay (3.03+dfsg2-8) ...
Selecting previously unselected package libtext-charwidth-perl.
Preparing to unpack .../libtext-charwidth-perl_0.04-10build3_amd64.deb ...
Unpacking libtext-charwidth-perl (0.04-10build3) ...
Setting up libtext-charwidth-perl (0.04-10build3) ...
Setting up cowsay (3.03+dfsg2-8) ...
rc=0
$ dpkg -l cowsay libtext-charwidth-perl | grep ^ii
ii cowsay 3.03+dfsg2-8 all configurable talking cow
ii libtext-charwidth-perl 0.04-10build3 amd64 get display widths of characters on the terminal
$ /usr/games/cowsay offline install
_________________
< offline install >
-----------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
解读:dpkg -i 接多个 .deb 时会先全部解包、再按依赖顺序统一配置(先 Setting up 依赖、再主包),rc=0 一次通过。这是离线装机的标准姿势——比单个安装再 install -f 更可控。
4.2 -C 审计 + --configure -a 修复闭环
场景:模拟「升级被打断」的半配置现场,走一遍标准修复流程:
$ cd /root && apt-get download sl 2>&1 | tail -1
W: Download is performed unsandboxed as root as file '/root/sl_5.02-1_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
$ dpkg --unpack /root/sl_*.deb >/dev/null; echo unpack_rc=$?
unpack_rc=0
$ dpkg -C
The following packages have been unpacked but not yet configured.
They must be configured using dpkg --configure or the configure
menu option in dselect for them to work:
sl Correct you if you type `sl' by mistake
$ dpkg --configure -a; echo rc=$?
Setting up sl (5.02-1) ...
rc=0
$ dpkg -C; echo rc=$?
rc=0
$ dpkg -l sl | tail -1
ii sl 5.02-1 amd64 Correct you if you type `sl' by mistake
解读:dpkg -C 发现解包未配置的 sl → dpkg --configure -a 统一收尾(输出 Setting up sl)→ 复查 -C 干净、状态 ii。生产上升级中断后的巡检顺序:-C 查现场 → --configure -a 收尾 → apt-get install -f 补依赖 → 再 -C 复查。
4.3 rc 残留巡检与批量清理
场景:长期运行的服务器上 dpkg -l 会积累一批 rc 状态行(删了程序但配置文件还在),定期批量清除:
$ dpkg -l | grep '^rc'
rc plocate 1.1.15-1ubuntu2 amd64 much faster locate
$ dpkg -l | grep '^rc' | awk '{print $2}' | xargs apt-get purge -y -o Dpkg::Use-Pty=0 2>&1 | tail -3
After this operation, 0 B of additional disk space will be used.
(Reading database ... 26320 files and directories currently installed.)
Purging configuration files for plocate (1.1.15-1ubuntu2) ...
$ dpkg -l | grep '^rc' | wc -l; echo rc=$?
0
rc=0
解读:grep '^rc' 揪出残留行,awk '{print $2}' 取包名列,交给 apt-get purge 批量清除配置文件,复查计数归 0。清 rc 残留前应确认这些包确实不再需要(rc 行的包程序已删,只是配置文件占着目录)。
五、注意事项与常见问题
Q1:dpkg -i 报 dependency problems - leaving unconfigured 怎么处理?
这是 dpkg「无依赖解析」的设计行为(3.3 节实测):包停在 iU 状态,rc=1。处理顺序:apt-get install -f -y 自动补依赖并完成配置;彻底断网时按 4.1 节把依赖包下齐后多包一次安装。不要用 --force-all 硬怼依赖,容易留下隐性损坏。
Q2:E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process NNNN (apt-get)?
dpkg/apt 共用前端锁,同一时间只允许一个写操作进程。本文实测遇到(另一 apt-get 进程存活期间执行 dpkg -i 报 dpkg frontend lock was locked by another process with pid NNNN,rc=2)。正确做法:ps aux | grep apt 确认进程 18610 之类是否仍在跑包操作,等它结束;确认无进程后锁会自动释放。严禁直接删 /var/lib/dpkg/lock* 文件——dpkg 官方 FAQ 明确警告这可能损坏锁区与系统状态。
Q3:dpkg -l 里的 rc、iU、un 都是坏状态吗?
不是。rc 只是有配置文件残留(正常,可按 4.3 清理);un 是「未安装且未登记」,是大量从未安装包的正常形态;iU 是解包未配置的中间态,若长期存在才说明安装被打断,需要 3.4 节的修复流程。真正异常的是含大写字母的组合(如 iF 半配置、iH 半安装)和 R 错误位。
Q4:dpkg -r 之后,为什么有的包在 dpkg -l 里变成 rc,有的直接消失?
取决于包是否带 conffiles(配置文件)。有 conffiles 的(如 plocate 的 /etc/updatedb.conf,实测保留)→ 状态 rc;没有的(如 sl)→ 记录直接消失。所以「dpkg -l 里查不到」不一定是没装过,也可能是删干净了。
Q5:dpkg -c 包.deb | head 结尾多出一行 dpkg-deb: error: tar subprocess was killed by signal (Broken pipe)?
管道下游 head 提前关闭读端,tar 收到 SIGPIPE 被杀,dpkg-deb 如实报告。清单本身完整(head 只取了前 8 行)。介意的话改成重定向到文件再截取,或接受这条无害报错。
Q6:apt-get download 报 W: Download is performed unsandboxed as root ... couldn't be accessed by user '_apt'?
以 root 身份在 _apt 用户无权访问的目录(如 /root)下载时的提示,文件本身完好可用。规避方法:换普通用户可写的目录(如 /tmp)执行下载,或忽略该警告。
Q7:安装后运行程序报 command not found 或 Error opening terminal?
分两类:找不到命令先查 dpkg -L 包名 | grep bin——Ubuntu 把游戏类程序装在 /usr/games(不在默认 PATH,需全路径执行,如 /usr/games/sl);能找到但运行报 Error opening terminal: unknown. 的(如 sl),是程序需要终端环境(TERM 变量),无终端的脚本/重定向环境里属正常现象。
六、参考链接
- Ubuntu 22.04 (jammy) dpkg(1) 手册页:https://manpages.ubuntu.com/manpages/jammy/en/man1/dpkg.1.html
- Debian dpkg(1) 手册页(在线版):https://manpages.debian.org/bookworm/dpkg/dpkg.1.en.html
- dpkg FAQ(含锁文件处理官方警告):https://wiki.debian.org/Teams/Dpkg/FAQ
- dpkg-deb(1) 手册页(.deb 操作族命令):https://manpages.ubuntu.com/manpages/jammy/en/man1/dpkg-deb.1.html
- Ubuntu Server 文档 · 软件包管理:https://documentation.ubuntu.com/server/how-to/software/package-management/