apt-get 命令详解与参数实测(Ubuntu 22.04)
apt-get 命令逐参数实测:update 与 apt 回显对照、install -y 纯文本输出、-s 模拟与 Inst/Conf 行解读、--no-install-recommends 对照、-d 只下载落缓存、-f 修复半安装态全流程(iU 到 ii)、autoremove --purge 清孤儿、--reinstall、clean 与 autoclean 前后对照、check 依赖检查与 rc=100,全部回显在 Ubuntu 22.04(apt 2.4.14)实测通过。
apt-get 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 apt-get 的每一个常用参数——update 与 apt 的回显对照、install
-y与纯文本输出、-s/--simulate模拟与 Inst/Conf 行解读、-d/--download-only只下载、-f/--fix-broken修复半安装态全流程(iU→ii)、autoremove --purge 清孤儿、--reinstall、clean 与 autoclean 的缓存前后对照、check 依赖完整性、rc=100 退出码,全部命令与回显已在 Ubuntu 22.04(apt 2.4.14)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64),root 身份执行
- APT 版本:apt-get 2.4.14(apt / apt-get / apt-cache 三件套同版本)
- 软件源:archive.ubuntu.com 与 security.ubuntu.com 的 jammy 全组件
- 演示包:tree 2.0.2-1、sl 5.02-1、cowsay 3.03+dfsg2-8、zip 3.0-12build2、unzip 6.0-26ubuntu3.2,另用 dpkg-deb 自制演示包 demo-app 1.0
- 缓存目录:
/var/lib/apt/lists/(索引)、/var/cache/apt/archives/(下载的 .deb) - apt-get 定位:APT 家族中历史最长的命令行前端,输出格式稳定、子命令最全,是脚本与自动化场景的官方推荐(apt(8) 手册明确建议脚本优先使用 apt-get 一类专用工具)
💡 技术拓展:apt-get 与 apt、apt-cache 的分工——apt-get 负责「变更」(装/删/升级/清理),apt-cache 负责「查询」(搜索/详情/依赖/优先级),apt 是两者常用功能的整合壳。本篇聚焦 apt-get;apt 与 apt-cache 的逐参数实测见本专栏姊妹篇。
二、命令概览
2.1 语法与测试数据
apt-get 的基本语法是 apt-get [options] command [package ...]:options 是短/长选项(本文主角),command 为子命令,package 为包名(写 libc6 而非 libc6.deb)。变更类子命令(install/remove/purge/autoremove/clean)需 root 权限,-s 模拟与查询类不受限。
先确认演示包在仓库中的版本:
$ apt-cache madison sl tree cowsay
sl | 5.02-1 | http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
tree | 2.0.2-1 | http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
cowsay | 3.03+dfsg2-8 | http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
自制演示包 demo-app 的设定:硬依赖 sl,自带一个 conffile(/etc/demo-app/demo.conf),用于 3.6 节的 -f 修复与 remove/purge 状态对照。
2.2 --help 全量输出
apt-get --help 全量回显(逐行照抄):
$ apt-get --help
apt 2.4.14 (amd64)
Usage: apt-get [options] command
apt-get [options] install|remove pkg1 [pkg2 ...]
apt-get [options] source pkg1 [pkg2 ...]
apt-get is a command line interface for retrieval of packages
and information about them from authenticated sources and
for installation, upgrade and removal of packages together
with their dependencies.
Most used commands:
update - Retrieve new lists of packages
upgrade - Perform an upgrade
install - Install new packages (pkg is libc6 not libc6.deb)
reinstall - Reinstall packages (pkg is libc6 not libc6.deb)
remove - Remove packages
purge - Remove packages and config files
autoremove - Remove automatically all unused packages
dist-upgrade - Distribution upgrade, see apt-get(8)
dselect-upgrade - Follow dselect selections
build-dep - Configure build-dependencies for source packages
satisfy - Satisfy dependency strings
clean - Erase downloaded archive files
autoclean - Erase old downloaded archive files
check - Verify that there are no broken dependencies
source - Download source archives
download - Download the binary package into the current directory
changelog - Download and display the changelog for the given package
See apt-get(8) for more information about the available commands.
Configuration options and syntax is detailed in apt.conf(5).
Information about how to configure sources can be found in sources.list(5).
Package and version choices can be expressed via apt_preferences(5).
Security details are available in apt-secure(8).
This APT has Super Cow Powers.
帮助列表里能看到 apt-get 比 apt 多出的一批子命令:purge、dist-upgrade、build-dep、clean、autoclean、check、source、download、changelog——这正是「脚本场景选 apt-get」的底气。
2.3 版本信息
$ apt-get --version
apt 2.4.14 (amd64)
Supported modules:
*Ver: Standard .deb
Pkg: Debian APT solver interface (Priority -1000)
Pkg: Debian APT planner interface (Priority -1000)
*Pkg: Debian dpkg interface (Priority 30)
S.L: 'deb' Debian binary tree
S.L: 'deb-src' Debian source tree
Idx: EDSP scenario file
Idx: EIPP scenario file
Idx: Debian Source Index
Idx: Debian Package Index
Idx: Debian Translation Index
Idx: Debian dpkg status file
Idx: Debian deb file
Idx: Debian dsc file
Idx: Debian control file
$ apt --version
apt 2.4.14 (amd64)
apt-get 的版本输出带模块清单(求解器、dpkg 接口、各类索引),排查索引解析问题时比 apt 的一行式输出更有信息量。
三、参数逐项实测
3.1 update 与 apt update 的回显对照
同样的缓存刷新,两个前端的输出形态不同。apt-get update 纯文本、止于 Reading package lists...:
$ apt-get update; echo rc=$?
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Hit:2 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu jammy-security InRelease
Reading package lists...
rc=0
apt update 则在 Hit/Get 行之后多出依赖树构建、状态读取与人类可读总结,输出重定向时还会附加稳定契约警告:
$ apt update; echo rc=$?
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Hit:2 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Hit:4 http://security.ubuntu.com/ubuntu jammy-security InRelease
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
rc=0
对照结论:Hit:N 表示源元数据未变化、复用本地缓存;Get:N 表示有变化重新下载(首次刷新时逐条 Get,形态与解读见 apt 篇 3.1)。apt-get 的输出少三个步骤行、无 WARNING,是最稳的脚本形态;apt 多的 All packages are up to date./N packages can be upgraded. 总结行是给人看的。缓存索引存放于 /var/lib/apt/lists/,apt-cache 的全部查询都以它为数据源。
💡 要点:两个命令刷的是同一份缓存,先后执行只影响 Hit/Get 形态,不影响结果;脚本里固定用
apt-get update并以 rc 判定成败。
3.2 install -y 与回显对照
-y/--yes 对所有确认点自动回答 yes,是免交互安装的标准选项。apt-get install 的完整回显:
$ apt-get install -y tree; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
tree
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 47.9 kB of archives.
After this operation, 116 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 tree amd64 2.0.2-1 [47.9 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 47.9 kB in 1s (46.3 kB/s)
Selecting previously unselected package tree.
(Reading database ... (Reading database ... 5%(Reading database ... 10%(Reading database ... 15%(Reading database ... 20%(Reading database ... 25%(Reading database ... 30%(Reading database ... 35%(Reading database ... 40%(Reading database ... 45%(Reading database ... 50%(Reading database ... 55%(Reading database ... 60%(Reading database ... 65%(Reading database ... 70%(Reading database ... 75%(Reading database ... 80%(Reading database ... 85%(Reading database ... 90%(Reading database ... 95%(Reading database ... 100%(Reading database ... 26312 files and directories currently installed.)
Preparing to unpack .../tree_2.0.2-1_amd64.deb ...
Unpacking tree (2.0.2-1) ...
Setting up tree (2.0.2-1) ...
rc=0
((Reading database ... 一行是 dpkg 读取本地数据库的进度回显,回车刷新导致实测日志中连为一行。)同样安装 apt 的形态几乎逐行相同,仅多一条 WARNING:
$ apt install -y tree; echo rc=$?
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
tree
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 47.9 kB of archives.
After this operation, 116 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 tree amd64 2.0.2-1 [47.9 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 47.9 kB in 1s (48.6 kB/s)
Selecting previously unselected package tree.
(Reading database ... (Reading database ... 5%(Reading database ... 10%(Reading database ... 15%(Reading database ... 20%(Reading database ... 25%(Reading database ... 30%(Reading database ... 35%(Reading database ... 40%(Reading database ... 45%(Reading database ... 50%(Reading database ... 55%(Reading database ... 60%(Reading database ... 65%(Reading database ... 70%(Reading database ... 75%(Reading database ... 80%(Reading database ... 85%(Reading database ... 90%(Reading database ... 95%(Reading database ... 100%(Reading database ... 26312 files and directories currently installed.)
Preparing to unpack .../tree_2.0.2-1_amd64.deb ...
Unpacking tree (2.0.2-1) ...
Setting up tree (2.0.2-1) ...
rc=0
对照结论:在输出重定向(非 TTY)环境下,两者的计划段(NEW/汇总行/Need to get)、下载段(Get/Fetched)、解包配置段(Unpacking/Setting up)完全一致;差异只有两点——apt 多打 WARNING,交互终端下 apt 有彩色与动态进度条而 apt-get 恒为纯文本。Need to get 与 After this operation 两行是变更前评估下载量与磁盘增量的关键;0 not upgraded 中的计数是本次不动的可升级包数(本机全部为最新时为 0)。
💡 要点:apt-get 无稳定契约警告、输出可预测,日志解析与断言应选 apt-get;apt 的进度条/彩色只在 TTY 有效。
3.3 -s/--simulate:模拟安装,不落地
-s(长选项 --simulate/--dry-run)完整跑一遍依赖求解并打印计划,但不下载、不解包、不改系统。以 cowsay 为例(它还带一个额外依赖与两条建议包):
$ apt-get -s install cowsay; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
libtext-charwidth-perl
Suggested packages:
filters cowsay-off
The following NEW packages will be installed:
cowsay libtext-charwidth-perl
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Inst libtext-charwidth-perl (0.04-10build3 Ubuntu:22.04/jammy [amd64])
Inst cowsay (3.03+dfsg2-8 Ubuntu:22.04/jammy [all])
Conf libtext-charwidth-perl (0.04-10build3 Ubuntu:22.04/jammy [amd64])
Conf cowsay (3.03+dfsg2-8 Ubuntu:22.04/jammy [all])
rc=0
Inst/Conf 行逐字段解读:Inst 包名 (版本 发行版/套件 [架构]) 是解包计划,Conf 包名 (版本 ...) 是配置计划,二者按执行顺序排列——版本约束或冲突问题在这一段就会现形。验证模拟确实未落地:
$ dpkg -l | grep cowsay || echo 'cowsay 未安装(-s 模拟未落地)'
cowsay 未安装(-s 模拟未落地)
💡 要点:任何可能产生大变更的操作(升级、批量装删、引入新源)先
apt-get -s预演,看The following packages will be REMOVED有没有不该删的包;模拟不消耗下载流量,rc 与真实执行同源。
3.4 --no-install-recommends:跳过推荐包(模拟对照)
依赖分三层:Depends 必装、Recommends 默认装、Suggests 只提示。zip Recommends unzip,正好做 A/B。默认计划(zip 带上 unzip,2 个新装):
$ apt-get -s install zip | grep -E 'Inst|newly installed'
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Inst unzip (6.0-26ubuntu3.2 Ubuntu:22.04/jammy-updates [amd64])
Inst zip (3.0-12build2 Ubuntu:22.04/jammy [amd64])
加 --no-install-recommends 后(只剩 zip 自己,1 个新装):
$ apt-get -s install --no-install-recommends zip | grep -E 'Inst|newly installed'
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Inst zip (3.0-12build2 Ubuntu:22.04/jammy [amd64])
用 -s 做对照的好处是全程零副作用:模拟完连 zip 都不必真装。两个计划的差集就是被跳过的推荐包(unzip)。需要真实安装对照(含 Recommended packages: 提示行与磁盘增量对比)可参考 apt 篇 3.3 的实测:默认 2 newly installed/930 kB,加参数后 1 newly installed/544 kB。
💡 要点:追求最小化安装集(精简系统、批量分发)时加
--no-install-recommends;代价是可能缺功能增强件,装完报错先想到这一层。
3.5 -d/--download-only:只下载不安装
-d(长选项 --download-only)把 .deb 下载到 /var/cache/apt/archives/ 后停止,不做解包配置:
$ apt-get install -y -d sl; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
sl
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 12.7 kB of archives.
After this operation, 60.4 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 sl amd64 5.02-1 [12.7 kB]
Fetched 12.7 kB in 1s (24.8 kB/s)
Download complete and in download only mode
rc=0
结尾的 Download complete and in download only mode 是 -d 模式的标志性收尾。确认 .deb 已落缓存(注意文件保留的是仓库里的原始修改时间):
$ ls -lh /var/cache/apt/archives/sl*
-rw-r--r-- 1 root root 13K Feb 2 2019 /var/cache/apt/archives/sl_5.02-1_amd64.deb
之后正常安装会直接命中缓存,Need to get 显示为 0 B/12.7 kB(0 B 表示无需网络下载):
$ apt-get install -y sl; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
sl
debconf: delaying package configuration, since apt-utils is not installed
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/12.7 kB of archives.
After this operation, 60.4 kB of additional disk space will be used.
Selecting previously unselected package sl.
(Reading database ... (Reading database ... 5%(Reading database ... 10%(Reading database ... 15%(Reading database ... 20%(Reading database ... 25%(Reading database ... 30%(Reading database ... 35%(Reading database ... 40%(Reading database ... 45%(Reading database ... 50%(Reading database ... 55%(Reading database ... 60%(Reading database ... 65%(Reading database ... 70%(Reading database ... 75%(Reading database ... 80%(Reading database ... 85%(Reading database ... 90%(Reading database ... 95%(Reading database ... 100%(Reading database ... 26320 files and directories currently installed.)
Preparing to unpack .../archives/sl_5.02-1_amd64.deb ...
Unpacking sl (5.02-1) ...
Setting up sl (5.02-1) ...
rc=0
Preparing to unpack .../archives/sl_5.02-1_amd64.deb ... 的路径证实解包用的就是缓存里的那份。另一个相近子命令 apt-get download 包名 则把 .deb 下载到当前目录(适合把包带走),-d 下载到缓存(适合本机稍后统一安装)。
💡 要点:离线安装流水线=先在有网的机器
-d或download攒包,再到目标机安装;-d 的包留在缓存供 apt 使用,download 的包在当前目录供人工搬运。
3.6 -f/--fix-broken:修复半安装态全流程(含 remove/purge 对照)
-f(长选项 --fix-broken)用于修复依赖缺失/损坏的「半安装态」。人为构造一个:自制 demo-app(Depends: sl,自带 conffile),先准备好构建材料与 sl 缺席的环境:
$ apt-get purge -y sl >/dev/null 2>&1; echo rc=$?
rc=0
$ rm -rf /tmp/demo-app /tmp/demo-app_1.0_amd64.deb; mkdir -p /tmp/demo-app/DEBIAN /tmp/demo-app/etc/demo-app
$ printf 'Package: demo-app\nVersion: 1.0\nArchitecture: amd64\nMaintainer: Demo <demo@example.com>\nDepends: sl\nDescription: Demo package with unmet dependency\n Used to demonstrate apt-get -f install.\n' > /tmp/demo-app/DEBIAN/control
$ printf '/etc/demo-app/demo.conf\n' > /tmp/demo-app/DEBIAN/conffiles
$ printf 'mode = demo\n' > /tmp/demo-app/etc/demo-app/demo.conf
$ dpkg-deb --build /tmp/demo-app /tmp/demo-app_1.0_amd64.deb; echo rc=$?
dpkg-deb: building package 'demo-app' in '/tmp/demo-app_1.0_amd64.deb'.
rc=0
用 dpkg -i 绕过依赖解析强行安装(sl 未装),dpkg 报依赖错误并留下未配置状态:
$ dpkg -i /tmp/demo-app_1.0_amd64.deb; echo rc=$?
Selecting previously unselected package demo-app.
(Reading database ... 26317 files and directories currently installed.)
Preparing to unpack /tmp/demo-app_1.0_amd64.deb ...
Unpacking demo-app (1.0) ...
dpkg: dependency problems prevent configuration of demo-app:
demo-app depends on sl; however:
Package sl is not installed.
dpkg: error processing package demo-app (--install):
dependency problems - leaving unconfigured
Errors were encountered while processing:
demo-app
rc=1
$ dpkg -l demo-app | tail -1
iU demo-app 1.0 amd64 Demo package with unmet dependency
状态 iU 的含义:第一位 i = expected install(已选择安装),第二位 U = unpacked(已解包未配置)——典型半安装态。此时执行 apt-get -f install,它会补齐缺失依赖并完成搁置的配置:
$ apt-get -f install -y; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
Correcting dependencies... Done
The following package was automatically installed and is no longer required:
liburing2
Use 'apt autoremove' to remove it.
The following additional packages will be installed:
sl
The following NEW packages will be installed:
sl
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
1 not fully installed or removed.
Need to get 12.7 kB of archives.
After this operation, 60.4 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 sl amd64 5.02-1 [12.7 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 12.7 kB in 1s (16.1 kB/s)
Selecting previously unselected package sl.
(Reading database ... 26319 files and directories currently installed.)
Preparing to unpack .../archives/sl_5.02-1_amd64.deb ...
Unpacking sl (5.02-1) ...
Setting up sl (5.02-1) ...
Setting up demo-app (1.0) ...
rc=0
回显里有三个修复信号:Correcting dependencies... Done、1 not fully installed or removed.(dpkg 数据库中有一个未完成包)、最后的 Setting up demo-app (1.0) ...(搁置的配置补跑完成)。验证状态归位:
$ dpkg -l demo-app sl | grep -E '^ii'
ii demo-app 1.0 amd64 Demo package with unmet dependency
ii sl 5.02-1 amd64 Correct you if you type `sl' by mistake
iU 变回 ii,修复闭环。随后是 remove/purge 的状态对照(demo-app 带 conffile,能观察到配置保留):remove 之后进入 rc 状态、配置文件原样保留:
$ apt-get remove -y demo-app; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following packages were automatically installed and are no longer required:
liburing2 sl
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
demo-app
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 0 B of additional disk space will be used.
(Reading database ... 26342 files and directories currently installed.)
Removing demo-app (1.0) ...
rc=0
$ dpkg -l demo-app | tail -1; cat /etc/demo-app/demo.conf
rc demo-app 1.0 amd64 Demo package with unmet dependency
mode = demo
purge 之后记录彻底消失、配置文件被删:
$ apt-get purge -y demo-app; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following packages will be REMOVED:
demo-app*
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 0 B of additional disk space will be used.
(Reading database ... 26342 files and directories currently installed.)
Purging configuration files for demo-app (1.0) ...
rc=0
$ dpkg -l demo-app
dpkg-query: no packages found matching demo-app
$ cat /etc/demo-app/demo.conf
cat: /etc/demo-app/demo.conf: No such file or directory
清理构建材料与演示依赖:
$ rm -rf /tmp/demo-app /tmp/demo-app_1.0_amd64.deb; apt-get purge -y sl >/dev/null 2>&1; echo rc=$?
rc=0
💡 技术拓展:dpkg 查询状态码速查(
dpkg -l前两列)——
状态 含义 常见触发 ii 已安装且配置完成 正常安装成功 iU 已解包未配置 dpkg -i 遇到依赖缺失 iF 半配置 配置脚本执行中断 iH 半安装 安装过程被打断 rc 已删除、配置残留 remove 带 conffile 的包 un 未知/未安装 从未安装或已彻底清除 与 -f 配合的另一个修复手段是
dpkg --configure -a(补跑所有未完成包的配置脚本),依赖缺失用 -f、配置中断用它,两者常一起排查。
3.7 autoremove --purge:清理孤儿依赖
作为依赖被自动装入的包,在依赖它的包删除后成为孤儿。复现完整链路:装 cowsay(自动带入 libtext-charwidth-perl)→ 删 cowsay → 孤儿出现:
$ apt-get install -y cowsay; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
libtext-charwidth-perl
Suggested packages:
filters cowsay-off
The following NEW packages will be installed:
cowsay libtext-charwidth-perl
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 28.7 kB of archives.
After this operation, 139 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/main amd64 libtext-charwidth-perl amd64 0.04-10build3 [10.2 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy/universe amd64 cowsay all 3.03+dfsg2-8 [18.6 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 28.7 kB in 1s (28.2 kB/s)
Selecting previously unselected package libtext-charwidth-perl.
(Reading database ... (Reading database ... 5%(Reading database ... 10%(Reading database ... 15%(Reading database ... 20%(Reading database ... 25%(Reading database ... 30%(Reading database ... 35%(Reading database ... 40%(Reading database ... 45%(Reading database ... 50%(Reading database ... 55%(Reading database ... 60%(Reading database ... 65%(Reading database ... 70%(Reading database ... 75%(Reading database ... 80%(Reading database ... 85%(Reading database ... 90%(Reading database ... 95%(Reading database ... 100%(Reading database ... 26320 files and directories currently installed.)
Preparing to unpack .../libtext-charwidth-perl_0.04-10build3_amd64.deb ...
Unpacking libtext-charwidth-perl (0.04-10build3) ...
Selecting previously unselected package cowsay.
Preparing to unpack .../cowsay_3.03+dfsg2-8_all.deb ...
Unpacking cowsay (3.03+dfsg2-8) ...
Setting up libtext-charwidth-perl (0.04-10build3) ...
Setting up cowsay (3.03+dfsg2-8) ...
rc=0
$ apt-get remove -y cowsay; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following package was automatically installed and is no longer required:
libtext-charwidth-perl
Use 'apt autoremove' to remove it.
The following packages will be REMOVED:
cowsay
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 93.2 kB disk space will be freed.
(Reading database ... (Reading database ... 5%(Reading database ... 10%(Reading database ... 15%(Reading database ... 20%(Reading database ... 25%(Reading database ... 30%(Reading database ... 35%(Reading database ... 40%(Reading database ... 45%(Reading database ... 50%(Reading database ... 55%(Reading database ... 60%(Reading database ... 65%(Reading database ... 70%(Reading database ... 75%(Reading database ... 80%(Reading database ... 85%(Reading database ... 90%(Reading database ... 95%(Reading database ... 100%(Reading database ... 26390 files and directories currently installed.)
Removing cowsay (3.03+dfsg2-8) ...
rc=0
$ dpkg -l cowsay libtext-charwidth-perl | grep -E '^(ii|rc)'
dpkg-query: no packages found matching cowsay
ii libtext-charwidth-perl 0.04-10build3 amd64 get display widths of characters on the terminal
cowsay 无 conffile,remove 后直接从数据库消失;libtext-charwidth-perl 还在(ii,等待清理)。apt-get autoremove --purge -y 一次清掉孤儿及其配置(包名带 * 表示连配置):
$ apt-get autoremove --purge -y; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
The following packages will be REMOVED:
libtext-charwidth-perl*
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 46.1 kB disk space will be freed.
(Reading database ... (Reading database ... 5%(Reading database ... 10%(Reading database ... 15%(Reading database ... 20%(Reading database ... 25%(Reading database ... 30%(Reading database ... 35%(Reading database ... 40%(Reading database ... 45%(Reading database ... 50%(Reading database ... 55%(Reading database ... 60%(Reading database ... 65%(Reading database ... 70%(Reading database ... 75%(Reading database ... 80%(Reading database ... 85%(Reading database ... 90%(Reading database ... 95%(Reading database ... 100%(Reading database ... 26330 files and directories currently installed.)
Removing libtext-charwidth-perl (0.04-10build3) ...
rc=0
$ dpkg -l | grep cowsay || echo 'cowsay 无残留'
cowsay 无残留
日常 install 输出中的 The following package was automatically installed and is no longer required 提示行即孤儿预告;批量安装/卸载后跑一次 apt-get autoremove --purge -y 是保持系统干净的常规动作。
💡 要点:autoremove 的名单由 auto 标记决定,误标会让关键包进回收名单——生产环境实跑前先
apt-get -s autoremove(模拟)看Remv名单,确认无误再加-y;--purge连配置一起清,确定不要配置时才加。
3.8 --reinstall:同版本重装
包文件被误删/损坏时,--reinstall 强制重新安装当前版本(汇总行显示 1 reinstalled,解包行为 over (2.0.2-1) 同版本覆盖):
$ apt-get install -y --reinstall tree; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 0 not upgraded.
Need to get 47.9 kB of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 tree amd64 2.0.2-1 [47.9 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 47.9 kB in 1s (34.8 kB/s)
(Reading database ... (Reading database ... 5%(Reading database ... 10%(Reading database ... 15%(Reading database ... 20%(Reading database ... 25%(Reading database ... 30%(Reading database ... 35%(Reading database ... 40%(Reading database ... 45%(Reading database ... 50%(Reading database ... 55%(Reading database ... 60%(Reading database ... 65%(Reading database ... 70%(Reading database ... 75%(Reading database ... 80%(Reading database ... 85%(Reading database ... 90%(Reading database ... 95%(Reading database ... 100%(Reading database ... 26320 files and directories currently installed.)
Preparing to unpack .../tree_2.0.2-1_amd64.deb ...
Unpacking tree (2.0.2-1) over (2.0.2-1) ...
Setting up tree (2.0.2-1) ...
rc=0
不带 --reinstall 对已装包执行 install,只会得到 tree is already the newest version (2.0.2-1). 并跳过(形态见 apt 篇 Q6)。
💡 要点:
--reinstall是「文件坏了但版本没变」时的唯一修复路径——apt 见到已装同版本就跳过,重装后dpkg -V校验应恢复干净。缓存被 clean 过也没关系,apt 会自动回源下载 .deb。
3.9 clean 与 autoclean:缓存清理的前后对照
先看清一个前提:本环境(apt 2.4)下普通 apt-get install 装完后 archives 里不留 .deb——实测缓存目录只有 0 个 deb、20K(仅 lock 与 partial/):
$ ls /var/cache/apt/archives/*.deb | wc -l; du -sh /var/cache/apt/archives
ls: cannot access '/var/cache/apt/archives/*.deb': No such file or directory
0
20K /var/cache/apt/archives
这是 apt 2.1.16 起的默认行为(APT::Keep-Downloaded-Packages 默认关闭,编译内置默认值,/etc/apt/apt.conf.d/ 下无显式配置)。所以 clean/autoclean 的演示需要先人为攒包:用 -d 下载 sl 与 tree 到缓存,出现 2 个 deb(84K):
$ apt-get clean; echo rc=$?
rc=0
$ ls /var/cache/apt/archives/; du -sh /var/cache/apt/archives
lock
partial
20K /var/cache/apt/archives
$ apt-get install -y -d sl tree >/dev/null 2>&1; echo rc=$?
rc=0
$ ls -lh /var/cache/apt/archives/*.deb
-rw-r--r-- 1 root root 13K Feb 2 2019 /var/cache/apt/archives/sl_5.02-1_amd64.deb
-rw-r--r-- 1 root root 47K Feb 18 2022 /var/cache/apt/archives/tree_2.0.2-1_amd64.deb
$ du -sh /var/cache/apt/archives
84K /var/cache/apt/archives
autoclean 只删「仓库里已不存在对应版本」的过期 deb——两个包都是仓库当前版本,所以删不了、84K 原样:
$ apt-get autoclean; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
rc=0
$ ls /var/cache/apt/archives/*.deb | wc -l; du -sh /var/cache/apt/archives
2
84K /var/cache/apt/archives
clean 无差别清空全部 deb,回到 20K 基线:
$ apt-get clean; echo rc=$?
rc=0
$ ls /var/cache/apt/archives/; du -sh /var/cache/apt/archives
lock
partial
20K /var/cache/apt/archives
💡 要点:磁盘紧张时清理顺序=autoclean(只清过期,无风险)→ clean(全清,下次重装要重新下载);
apt-get clean的 rc 恒为 0,即使无事可做。
3.10 check:依赖完整性检查
apt-get check 校验本机全部已装包的依赖关系是否自洽,健康时输出极简、rc=0:
$ apt-get check; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
rc=0
它是变更后的低成本体检:任何依赖环破损、半安装态都会让它报 E 并返回非 0,适合放进脚本做安装后断言。
💡 要点:
apt-get check只查依赖一致性,不校验文件内容(那是dpkg --verify的职责);两者配合构成「依赖体检 + 文件体检」双断言,批量安装脚本收尾时各跑一次,失败即中止后续步骤。
3.11 -t/--target-release 与 changelog、download
三个低频但实用点一句话带过:
-t 发行版代称(长选项--target-release):把本次操作的候选版本临时定向到指定套件,例如apt-get install -t jammy-backports 包名临时启用 backports 版本;需长期生效应改 apt_preferences(pin 优先级,解读见 apt-cache 篇 policy 一节)。apt-get changelog 包名:在线拉取并显示软件包的变更日志,排查「这个版本改了什么」时好用(依赖网络,本文不实跑)。apt-get download 包名:把 .deb 下载到当前目录而非缓存,配合 scp 即可把包搬到离线机器(与 3.5 的-d互补)。
💡 要点:
-t是「只此一次」的临时定向,退出命令行即失效;要持久生效必须写/etc/apt/preferences钉扎优先级。两者最大的区别在可审计性——pin 写在文件里有据可查,-t藏在历史命令里,生产环境优先用 pin。
3.12 退出码:rc=100
仓库中找不到包时 apt-get 报 E 并返回 100,这是 APT 家族的约定错误码(0=成功,100=依赖/仓库类错误):
$ apt-get install -y demo-not-exist; echo rc=$?
Reading package lists...
Building dependency tree...
Reading state information...
E: Unable to locate package demo-not-exist
rc=100
同样的 rc=100 也会出现在对从未安装过的包名执行 remove/purge 时(如 3.6 构造前的 E: Unable to locate package demo-app)。脚本判成败用 $? 是否为 0;拿到 100 先核对包名与源配置。
💡 要点:apt-get 的错误码三分法——0 成功、100 依赖/仓库类错误、其他非 0(如 1)为执行中断类失败。巡检脚本按「非 0 即报警、100 单独走『查源配置』分支」处理,能把「包名写错」与「网络/源故障」两类问题自动分流。
四、实战示例
4.1 脚本化安装的标准范式
模拟预演 → 实装 → 校验,三段式降低变更风险:
apt-get -s install -y --no-install-recommends tree
apt-get install -y --no-install-recommends tree
rc=$?
[ $rc -eq 0 ] && dpkg -l tree | grep -q '^ii' && echo OK
-s 输出中确认没有意外 REMOVED 后再实装;rc 与 dpkg 状态双断言(回显形态分别见 3.3/3.2/3.6)。
4.2 离线装包流水线
有网机器攒包 → 目标机安装:
apt-get install -y -d sl tree # 下载到 /var/cache/apt/archives/
ls -lh /var/cache/apt/archives/*.deb # 核对包与原始时间戳
apt-get install -y sl tree # 命中缓存,Need to get 显示 0 B
跨机分发场景把 archives 下的 deb 拷走,或改用 apt-get download 包名 直接落到当前目录再带走。
4.3 半安装态救援
dpkg -i 装坏之后的修复闭环(全程实测见 3.6):
dpkg -i /tmp/demo-app_1.0_amd64.deb # 报依赖错误,留下 iU
dpkg -l demo-app | tail -1 # 确认 iU 状态
apt-get -f install -y # 补依赖并补配置
apt-get check # 依赖完整性复核
修复后 dpkg -l 应看到 ii,apt-get check 应 rc=0。
4.4 缓存空间治理
定期巡检与清理(前后对照实测见 3.9):
du -sh /var/cache/apt/archives
apt-get autoclean
apt-get clean
du -sh /var/cache/apt/archives
五、注意事项与常见问题
Q1:apt-get 和 apt 到底选哪个? A:apt(8) 手册原文明确:All features of apt(8) are available in dedicated APT tools like apt-get(8) and apt-cache(8) as well. ... So you should prefer using those commands (potentially with some additional options enabled) in your scripts.——脚本与自动化优先 apt-get;apt-get(8) 的自我定位是 the command-line tool for handling packages,输出契约稳定。交互场景用 apt(多了总结行与进度体验)。本篇 3.1/3.2 的对照实测显示:重定向下两者回显几乎一致,apt 仅多一条 WARNING。
Q2:-s 模拟的结果可信吗?
A:依赖求解与真实执行同源,计划部分(Inst/Conf、汇总行)完全可信;差异在于模拟不下载不解包,因此网络类问题(源不可达、校验失败)不会在 -s 阶段暴露。另外 root 身份执行时模拟输出不带额外声明行,直接以 Inst/Conf 呈现(见 3.3 实测)。
Q3:为什么装完包 /var/cache/apt/archives 是空的?
A:apt 2.1.16 起 APT::Keep-Downloaded-Packages 默认关闭,安装完成后 .deb 即被清理(实测 3.9 开头:0 个 deb、20K)。想让 deb 留存:用 -d 下载不安装,或自建 /etc/apt/apt.conf.d/ 配置写 APT::Keep-Downloaded-Packages "true";。
Q4:-f 修复会不会误删包?
A:apt-get -f install 的第一优先策略是补齐缺失依赖让所有包达成一致(实测 3.6 中它选择了安装 sl);当缺失依赖无法满足时它可能提议移除制造冲突的包,因此修复前先看它的计划段,拿不准就 -s 预演。配置脚本中断(iF)类问题要用 dpkg --configure -a 而非 -f。
Q5:rc=100 都在什么场景出现?
A:实测两类——安装仓库中不存在的包(3.12 的 E: Unable to locate package)、对数据库中不存在的包名执行 remove/purge。共同特征是包名/源配置问题,先 apt-get update 刷新再核对拼写;rc=2 则多来自 dpkg 底层(如构建的 deb 结构非法,见 Q6)。
Q6:自制 .deb 时报 conffile name is not an absolute pathname?
A:dpkg 1.21.1 起 DEBIAN/conffiles 必须写绝对路径。实测踩坑全程(写相对路径 etc/demo-app/demo.conf):
$ printf 'etc/demo-app/demo.conf\n' > /tmp/demo-app/DEBIAN/conffiles
$ dpkg-deb --build /tmp/demo-app /tmp/demo-app_1.0_amd64.deb; echo rc=$?
dpkg-deb: error: conffile name 'etc/demo-app/demo.conf' is not an absolute pathname
rc=2
后续 dpkg -i 会因 deb 不存在连锁报 cannot access archive。改为 /etc/demo-app/demo.conf 后构建成功(见 3.6)。
Q7:安装回显里的 debconf: delaying package configuration, since apt-utils is not installed 要处理吗?
A:只是提示——没装 apt-utils 时,包配置推迟到全部解包完成后统一进行,功能不受影响。在意回显整洁或需要实时配置进度的话,装上 apt-utils 即可消除。
Q8:autoremove 会不会误删我需要的东西?
A:autoremove 只处理状态为 automatic 且无任何已装包依赖的包;手动安装的包(manual)永远不会被它碰。执行前看 The following packages will be REMOVED 清单,或先 apt-get -s autoremove 预演(实测形态见 apt 篇 3.8 的 Remv 行)。确定某个自动包要长期保留,用 apt-mark manual 包名 改标记。
六、参考链接
- apt-get(8) 手册(Ubuntu 22.04 jammy 版):https://manpages.ubuntu.com/manpages/jammy/en/man8/apt-get.8.html
- apt(8) 手册(脚本选型官方说明):https://manpages.ubuntu.com/manpages/jammy/en/man8/apt.8.html
- apt.conf(5) 配置项(Keep-Downloaded-Packages 等):https://manpages.ubuntu.com/manpages/jammy/en/man5/apt.conf.5.html
- sources.list(5) 软件源配置:https://manpages.ubuntu.com/manpages/jammy/en/man5/sources.list.5.html
- dpkg(1) 与查询状态码:https://manpages.ubuntu.com/manpages/jammy/en/man1/dpkg.1.html
- dpkg-deb(1) 构建 .deb:https://manpages.ubuntu.com/manpages/jammy/en/man1/dpkg-deb.1.html
- Debian Wiki AptCLI:https://wiki.debian.org/AptCLI