apt 命令详解与参数实测(Ubuntu 22.04)
apt 命令逐参数实测:update 回显逐行解读、install 多包与 --no-install-recommends 对照、指定版本安装、remove 与 purge 的 ii/rc 状态对照、autoremove 清孤儿、search/show/list 三板斧、upgrade 与 full-upgrade 差异、缓存目录与 rc=100 退出码,全部回显在 Ubuntu 22.04(apt 2.4.14)实测通过。
apt 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 apt 的每一个常用参数——update 缓存刷新回显逐行解读、install 的
-y/多包/指定版本/--no-install-recommends/--reinstall、remove 与 purge 的 ii/rc 状态对照、autoremove、search 排序、show 字段解读、list 三种清单、upgrade 与 full-upgrade 差异、-q、缓存目录与退出码,全部命令与回显已在 Ubuntu 22.04(apt 2.4.14)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64),root 身份执行
- APT 版本:apt 2.4.14(
apt --version实测,apt / apt-get / apt-cache 三件套同为 2.4.14) - 软件源:archive.ubuntu.com 与 security.ubuntu.com 的 jammy 全组件(main/restricted/universe/multiverse)
- 演示包:sl 5.02-1、tree 2.0.2-1、cowsay 3.03+dfsg2-8、zip 3.0-12build2、unzip 6.0-26ubuntu3.2(均为仓库真实版本)
- 软件包列表缓存目录:
/var/lib/apt/lists/;下载缓存目录:/var/cache/apt/archives/ - apt 是 Ubuntu 16.04 起官方主推的 APT 交互前端,整合了 apt-get 与 apt-cache 的常用功能
💡 技术拓展:Debian 系的包管理工作不止 apt 一个,常见前端对比如下——
工具 定位 适用场景 dpkg 底层包操作(安装/查询本地 .deb,不解析网络依赖) 离线 .deb、查文件归属 apt-get 老牌命令行前端,输出稳定、面向脚本 自动化脚本、CI apt-cache 只读查询前端(搜索/详情/依赖/优先级) 仓库信息检索 apt 面向人的交互式整合前端(本篇主角) 日常手敲运维 aptitude 交互式 TUI 前端,冲突解决能力强 复杂依赖冲突处理 本文讲解 apt 本体;apt-get、apt-cache 的逐参数实测见本专栏姊妹篇,四者共享同一套底层仓库缓存。
二、命令概览
2.1 语法与测试数据
apt 的基本语法是 apt [options] command [package ...]:command 为子命令(update/install/remove 等),package 为软件包名(写包名本身,不带 .deb 后缀)。apt 需 root 权限执行安装/删除/刷新类操作,查询类(search/show/list)普通用户即可。
本篇所有演示围绕以下四个轻量包展开,先确认它们在仓库中的版本(unzip 在三个源里各有版本,madison 一并列出):
$ apt-cache madison sl tree cowsay unzip
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
unzip | 6.0-26ubuntu3.2 | http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages
unzip | 6.0-26ubuntu3.1 | http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages
unzip | 6.0-26ubuntu3 | http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages
环境软件源(/etc/apt/sources.list,节选):
$ grep -rE '^deb ' /etc/apt/sources.list | head -6
deb http://archive.ubuntu.com/ubuntu/ jammy main restricted
deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted
deb http://archive.ubuntu.com/ubuntu/ jammy universe
deb http://archive.ubuntu.com/ubuntu/ jammy-updates universe
deb http://archive.ubuntu.com/ubuntu/ jammy multiverse
deb http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse
2.2 --help 全量输出
apt --help 全量回显如下(逐行照抄):
$ apt --help
apt 2.4.14 (amd64)
Usage: apt [options] command
apt is a commandline package manager and provides commands for
searching and managing as well as querying information about packages.
It provides the same functionality as the specialized APT tools,
like apt-get and apt-cache, but enables options more suitable for
interactive use by default.
Most used commands:
list - list packages based on package names
search - search in package descriptions
show - show package details
install - install packages
reinstall - reinstall packages
remove - remove packages
autoremove - Remove automatically all unused packages
update - update list of available packages
upgrade - upgrade the system by installing/upgrading packages
full-upgrade - upgrade the system by removing/installing/upgrading packages
edit-sources - edit the source information file
satisfy - satisfy dependency strings
See apt(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 的定位:它提供与 apt-get / apt-cache 相同的功能,但默认启用更适合交互使用的选项。
2.3 版本信息
$ apt --version
apt 2.4.14 (amd64)
$ 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-cache --version
apt 2.4.14 (amd64)
apt --version 只输出一行版本号;apt-get --version 会额外列出支持模块(求解器、dpkg 接口、各类索引格式),排查索引/求解器问题时这一段更有参考价值。
三、参数逐项实测
3.1 update:刷新软件包列表缓存
apt 的所有安装/查询都依赖本地缓存(/var/lib/apt/lists/),因此任何操作前先 apt update。首次刷新(缓存为空)时每条索引都走 Get::
$ apt update; echo rc=$?
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Get:1 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Get:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
Get:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [127 kB]
Get:5 http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages [17.5 MB]
Get:6 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1325 kB]
Get:7 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [4429 kB]
Get:8 http://archive.ubuntu.com/ubuntu jammy/restricted amd64 Packages [164 kB]
Get:9 http://archive.ubuntu.com/ubuntu jammy/multiverse amd64 Packages [266 kB]
Get:10 http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages [1792 kB]
Get:11 http://archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [8243 kB]
Get:12 http://archive.ubuntu.com/ubuntu jammy-updates/multiverse amd64 Packages [104 kB]
Get:13 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [4758 kB]
Get:14 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1627 kB]
Get:15 http://archive.ubuntu.com/ubuntu jammy-backports/main amd64 Packages [82.9 kB]
Get:16 http://archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [35.6 kB]
Get:17 http://security.ubuntu.com/ubuntu jammy-security/multiverse amd64 Packages [96.8 kB]
Get:18 http://security.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [7955 kB]
Fetched 49.0 MB in 5s (9619 kB/s)
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
rc=0
回显逐行解读:
Get:N URL 描述 [大小]:第 N 号下载任务,本次真实下载了该索引文件(InRelease 是元数据签名清单,Packages 是包索引);方括号内是文件大小。Fetched 49.0 MB in 5s (9619 kB/s):本轮共下载的总量、耗时与平均速率。Reading package lists.../Building dependency tree.../Reading state information...:解析索引、构建依赖树、读取 dpkg 状态三步,全部成功才有后续总结。All packages are up to date.:总结行——没有可升级包;若有则会显示N packages can be upgraded. Run 'apt list --upgradable' to see them.WARNING: apt does not have a stable CLI interface. Use with caution in scripts.:apt 检测到输出被重定向(非交互终端)时打印的警告,含义见「五、注意事项」Q1。rc=0:成功退出码。
缓存已在本地时,同样的命令全部命中缓存(Hit: 形态,不再下载):
$ 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 表示该源的 InRelease 元数据校验后未变化,直接复用本地缓存,因此不再出现 Packages 下载行。生产上最常见的两种行就是 Hit(没变化)与 Get(有变化重新拉取)。
第三个常见形态是 Err:(取回失败)。临时加入一个不可达软件源实测:
$ echo 'deb http://mirrors.invalid.example/ubuntu/ jammy main' > /etc/apt/sources.list.d/demo-bad.list
$ 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://security.ubuntu.com/ubuntu jammy-security InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Ign:5 http://mirrors.invalid.example/ubuntu jammy InRelease
Ign:5 http://mirrors.invalid.example/ubuntu jammy InRelease
Ign:5 http://mirrors.invalid.example/ubuntu jammy InRelease
Err:5 http://mirrors.invalid.example/ubuntu jammy InRelease
Could not resolve 'mirrors.invalid.example'
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
W: Failed to fetch http://mirrors.invalid.example/ubuntu/dists/jammy/InRelease Could not resolve 'mirrors.invalid.example'
W: Some index files failed to download. They have been ignored, or old ones used instead.
rc=0
解读:Ign:N 是重试前的忽略标记(域名解析失败重试三次),Err:N 给出最终失败原因(本例为域名无法解析),末尾两条 W: 说明失败索引被忽略、改用旧缓存。注意单个源失败只会警告,rc 仍为 0;只有安装时缺包才会以 rc=100 报错(见 3.16)。删掉坏源后恢复:
$ rm /etc/apt/sources.list.d/demo-bad.list; apt update; echo rc=$?
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Hit:1 http://security.ubuntu.com/ubuntu jammy-security InRelease
Hit:2 http://archive.ubuntu.com/ubuntu jammy InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
rc=0
💡 要点:
Hit= 无变化用缓存,Get= 有变化重新下载,Ign= 重试中,Err= 最终失败(伴随 W: 警告);排查「apt update 慢/失败」先看 Err 行的域名与原因。
3.2 install:安装软件包(-y 与多包)
apt install 默认在交互终端询问确认;加 -y(--yes)对所有确认点自动回答 yes,是自动化操作的标准姿势。一次安装多个包直接并列写出:
$ apt install -y sl 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:
sl tree
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 60.6 kB of archives.
After this operation, 176 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]
Get:2 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 60.6 kB in 1s (53.6 kB/s)
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 ... 26312 files and directories currently installed.)
Preparing to unpack .../archives/sl_5.02-1_amd64.deb ...
Unpacking sl (5.02-1) ...
Selecting previously unselected package tree.
Preparing to unpack .../tree_2.0.2-1_amd64.deb ...
Unpacking tree (2.0.2-1) ...
Setting up sl (5.02-1) ...
Setting up tree (2.0.2-1) ...
rc=0
((Reading database ... 一行是 dpkg 查询本地数据库的进度回显, carriage-return 刷新导致连成一行,实测原文如此。)回显分四段:
- 计划段:
The following NEW packages will be installed列出将要新装的包;0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.汇总升级/新装/删除/不动四类数量;Need to get与After this operation分别预估下载量与磁盘增量——安装前判断影响面就看这四行。 - 下载段:
Get:N逐包下载,Fetched汇总。 - 解包段:
Selecting→Unpacking逐包解压。 - 配置段:
Setting up逐包执行 maintainer 脚本完成配置。
debconf: delaying package configuration, since apt-utils is not installed 是提示行:未装 apt-utils 时包配置被推迟到全部解包完成后统一进行,不影响结果。
验证安装结果:
$ dpkg -l sl tree | grep -E '^ii'
ii sl 5.02-1 amd64 Correct you if you type `sl' by mistake
ii tree 2.0.2-1 amd64 displays an indented directory tree, in color
💡 要点:
ii是 dpkg 状态码——第一位 i=installed,第二位 i=-installed(配置完成),它是「安装成功」的机器可判据。
3.3 install --no-install-recommends:不装推荐包
依赖分三层:Depends(硬依赖,必装)、Recommends(推荐,默认装)、Suggests(建议,默认不装)。zip 恰好 Recommends unzip,用它做对照。默认安装(推荐包一并装上,2 个新包):
$ apt install -y zip; 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 additional packages will be installed:
unzip
The following NEW packages will be installed:
unzip zip
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 350 kB of archives.
After this operation, 930 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 unzip amd64 6.0-26ubuntu3.2 [175 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy/main amd64 zip amd64 3.0-12build2 [176 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 350 kB in 2s (186 kB/s)
Selecting previously unselected package unzip.
(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 ... 26311 files and directories currently installed.)
Preparing to unpack .../unzip_6.0-26ubuntu3.2_amd64.deb ...
Unpacking unzip (6.0-26ubuntu3.2) ...
Selecting previously unselected package zip.
Preparing to unpack .../zip_3.0-12build2_amd64.deb ...
Unpacking zip (3.0-12build2) ...
Setting up unzip (6.0-26ubuntu3.2) ...
Setting up zip (3.0-12build2) ...
rc=0
清掉两个包后加 --no-install-recommends 重新安装(只有 1 个新包):
$ apt install -y --no-install-recommends zip; 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...
Recommended packages:
unzip
The following NEW packages will be installed:
zip
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 176 kB of archives.
After this operation, 544 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/main amd64 zip amd64 3.0-12build2 [176 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 176 kB in 2s (101 kB/s)
Selecting previously unselected package zip.
(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 ... 26311 files and directories currently installed.)
Preparing to unpack .../zip_3.0-12build2_amd64.deb ...
Unpacking zip (3.0-12build2) ...
Setting up zip (3.0-12build2) ...
rc=0
对照结论:默认安装 2 newly installed、磁盘增量 930 kB;加 --no-install-recommends 后 1 newly installed、磁盘增量 544 kB,被跳过的 unzip 以 Recommended packages: 行列出。服务器追求精简(比如构建最小化的基础系统、裁剪非必要组件)时常用该参数,但要清楚被省掉的推荐包可能是功能增强件。
💡 要点:对照口诀——Depends 必装、Recommends 默认装(
--no-install-recommends可关)、Suggests 默认不装。
3.4 install --reinstall:重装软件包
包文件损坏或误删部分文件时,--reinstall 强制重新安装当前版本(即使版本号没变):
$ apt install -y --reinstall 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...
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 (35.5 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 ... 26343 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
关键差异:汇总行变成 1 reinstalled,解包行是 Unpacking tree (2.0.2-1) over (2.0.2-1)(同版本覆盖),磁盘增量为 0 B。不带 --reinstall 重复安装已装包则什么都不做(见「五、常见问题」Q6 的 already the newest version 回显)。
💡 要点:
--reinstall典型场景是「二进制文件被误删/改坏但版本没变」——apt 默认见到已装的同版本就直接跳过,不加该参数永远拿不回文件。它重装的是缓存里的 .deb;若/var/cache/apt/archives已被clean清空,apt 会自动回源重新下载,无需人工干预。
3.5 install 指定版本:madison 查版本 + pkg=version
安装指定版本的语法是 apt install 包名=版本号。先用 apt-cache madison 查仓库里实际可用的版本(apt-cache 是只读查询工具,输出即真实版本表):
$ apt-cache madison sl
sl | 5.02-1 | http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
按查到的版本号精确安装:
$ apt install -y sl=5.02-1; 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:
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]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 12.7 kB in 1s (21.4 kB/s)
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
若指定的版本号在仓库中不存在,apt 会报 E: Version 'x.y' for 'pkg' was not found 并以 rc=100 退出。把已装的新版本降级到旧版本属于「降级」操作,默认会被拒绝,需要显式加 --allow-downgrades:
apt install --allow-downgrades -y 包名=旧版本号
本环境每个包在源里只有一个版本(madison 只列出一行),无法现场演示真实降级,但语法与约束如上:不加 --allow-downgrades 时 apt 拒绝把 Installed 版本换成更低优先级的版本,这是防止误降级的保护机制。
💡 要点:
包名=版本号的价值在于锁死变动——重放历史环境、绕过有缺陷的新版本时用它最稳。配合apt-cache madison 包名先查可用版本再装,避免猜版本号报 rc=100;降级属例外操作,--allow-downgrades每次显式携带,防止脚本里意外把生产组件降回旧版。
3.6 remove:卸载但保留配置(ii → rc 对照)
apt remove 删除程序与数据文件,但保留 conffile(包自带的 /etc 配置文件)。为了拿到可验证的「保留配置」证据,自制一个带 conffile 的演示包(由 dpkg-deb 构建,sl 是它的硬依赖):
$ 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 for remove and purge comparison\n Ships one conffile at /etc/demo-app/demo.conf.\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 /tmp/demo-app_1.0_amd64.deb; echo rc=$?
Selecting previously unselected package demo-app.
(Reading database ... 26340 files and directories currently installed.)
Preparing to unpack /tmp/demo-app_1.0_amd64.deb ...
Unpacking demo-app (1.0) ...
Setting up demo-app (1.0) ...
rc=0
$ dpkg -l demo-app | tail -1
ii demo-app 1.0 amd64 Demo package for remove and purge comparison
$ cat /etc/demo-app/demo.conf
mode = demo
执行 remove:
$ apt remove -y demo-app; 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 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
remove 之后包进入 rc 状态,且配置文件还在:
$ dpkg -l demo-app | tail -1
rc demo-app 1.0 amd64 Demo package for remove and purge comparison
$ cat /etc/demo-app/demo.conf
mode = demo
对照结论:dpkg 状态从 ii 变为 rc——r = removed(程序已删),c = config-files(配置残留);/etc/demo-app/demo.conf 内容原样保留。
💡 要点:remove 与 purge 的差别只在 conffile(
/etc下的声明式配置文件),对用户家目录里的点文件(如~/.config/xxx)两者都不清理——apt 只认 dpkg 登记过的 conffile。想彻底清场,先apt purge 包名再手工排查家目录残留。
3.7 purge:连配置一起删(rc → 消失)
在 rc 状态上执行 apt purge,配置文件一并清除:
$ apt purge -y demo-app; 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 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
三个信号确认 purge 生效:包名行变成 demo-app*(星号表示连配置清除)、回显出现 Purging configuration files for demo-app (1.0) ...、dpkg 数据库中该包记录彻底消失。
💡 要点:remove 保留配置(ii→rc),purge 连配置删除(rc→无记录);对从未装过的包直接 purge 等价于一次完整卸载。想把系统里历史遗留的 rc 包清干净,见下一节 autoremove。
3.8 autoremove 与 autoremove --purge:清理孤儿依赖
作为依赖被自动装入(状态标记 automatic)的包,在「依赖它的包」被删除后就成为孤儿。cowsay 的硬依赖 libtext-charwidth-perl 就是现成例子——先装 cowsay(依赖被自动带入):
$ apt install -y cowsay; 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 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 (33.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 ... 26325 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
注意 Suggested packages: filters cowsay-off——Suggests 只列出、不安装(与 3.3 的 Recommends 对照)。删除 cowsay 后,apt 立刻提示 libtext-charwidth-perl 成为孤儿:
$ apt remove -y cowsay; 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 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 ... 26395 files and directories currently installed.)
Removing cowsay (3.03+dfsg2-8) ...
rc=0
先用 -s 模拟(不落地)预览 autoremove 将删除什么——apt-get -s autoremove 的 Remv 行就是操作预演:
$ apt-get -s autoremove
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.
Remv libtext-charwidth-perl [0.04-10build3]
实跑 autoremove --purge(删除孤儿并顺带清除其配置,包名带 * 标记):
$ apt autoremove --purge -y; 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 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 ... 26335 files and directories currently installed.)
Removing libtext-charwidth-perl (0.04-10build3) ...
rc=0
不带 --purge 的裸 apt autoremove 行为相同但不删配置(等价于对每个孤儿执行 remove)。另外,日常 install 输出里频繁出现的 The following package was automatically installed and is no longer required 提示行,指的就是这类待 autoremove 的孤儿。
💡 要点:autoremove 的安全性完全取决于 auto/manual 标记是否准确——某关键包被误标 auto 且不再被依赖时,它就会进回收名单(因此 Ubuntu 24.04 起 autoremove 默认要求二次确认)。生产上养成「先
-s模拟看Remv名单,再实跑」的习惯;--purge只在确定连配置也不要时使用。
3.9 search:搜索软件包
按关键词搜索(包名与描述全文匹配),结果带「包名/源内版本/架构」头行与一行描述,且按相关度排序:
$ apt search cowsay
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Sorting...
Full Text Search...
cowsay/jammy 3.03+dfsg2-8 all
configurable talking cow
cowsay-off/jammy 3.03+dfsg2-8 all
configurable talking cow (offensive cows)
xcowsay/jammy 1.6-1 amd64
Graphical configurable talking cow
Sorting... 即相关度排序过程;头行格式为 包名/套件 版本 架构,已安装的包还会在方括号里标注 [installed]。用描述词做全文检索同样命中(cowsay 系列的描述都含 talking cow):
$ apt search 'talking cow'
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Sorting...
Full Text Search...
cowsay/jammy 3.03+dfsg2-8 all
configurable talking cow
cowsay-off/jammy 3.03+dfsg2-8 all
configurable talking cow (offensive cows)
xcowsay/jammy 1.6-1 amd64
Graphical configurable talking cow
--names-only 把匹配范围限制在包名,可配合正则做精确检索(^sl$ 只匹配名为 sl 的包):
$ apt search --names-only '^sl$'
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Sorting...
Full Text Search...
sl/jammy 5.02-1 amd64
Correct you if you type `sl' by mistake
💡 要点:不知道确切包名时先
apt search 关键词,命中后用apt show 包名看详情;要严格按包名过滤就加--names-only与正则锚点。
3.10 show:查看包详情(字段逐项解读)
$ apt show sl
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Package: sl
Version: 5.02-1
Priority: optional
Section: universe/games
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Markus Frosch <lazyfrosch@debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 60.4 kB
Depends: libc6 (>= 2.2.5), libncurses6 (>= 6), libtinfo6 (>= 6)
Homepage: https://github.com/mtoyoda/sl
Download-Size: 12.7 kB
APT-Sources: http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
Description: Correct you if you type `sl' by mistake
关键字段解读:
Version:仓库候选版本,可直接用于apt install sl=5.02-1。Priority: optional:包优先级;Section: universe/games表示来自 universe 组件的游戏类。Installed-Size:装完占用的磁盘量;Download-Size:.deb 下载量。Depends:硬依赖及版本约束(>= 2.2.5等),安装时自动解决。APT-Sources:该版本来自哪个源的哪个组件——判断「包从哪来」最直接的一行。Description:一句话描述。
再看 cowsay 的详情头部,注意它多出的 Suggests 行(对应 3.3 的三层依赖):
$ apt show cowsay | head -16
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Package: cowsay
Version: 3.03+dfsg2-8
Priority: optional
Section: universe/games
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: James McDonald <james@jamesmcdonald.com>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 93.2 kB
Depends: libtext-charwidth-perl, perl:any
Suggests: filters, cowsay-off
Homepage: https://web.archive.org/web/20120527202447/http://www.nog.net/~tony/warez/cowsay.shtml
Download-Size: 18.6 kB
APT-Sources: http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages
Description: configurable talking cow
💡 要点:
apt show的字段与apt-cache show同源(都读本地缓存),但 apt 版本会追加APT-Sources等安装视角行,更适合「装之前核对包从哪来」;Suggests行是可选增强件,装不装都不影响功能。脚本解析建议用dpkg-query(对已装包)或精确 grep 字段,别解析整段文本。
3.11 list:三种清单(--installed / --upgradable / --manual-installed)
apt list 按 installed 状态列出本机全部包,每行格式为 包名/套件,now 版本 架构 [状态]:
$ apt list --installed | head -8
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Listing...
adduser/jammy,now 3.118ubuntu5 all [installed]
apparmor/jammy-updates,now 3.0.4-2ubuntu2.5 amd64 [installed,automatic]
apt/jammy-updates,now 2.4.14 amd64 [installed]
base-files/jammy-updates,now 12ubuntu4.7 amd64 [installed]
base-passwd/jammy,now 3.5.52build1 amd64 [installed]
bash/jammy-updates,jammy-security,now 5.1-6ubuntu1.1 amd64 [installed]
bc/jammy,now 1.07.1-3build1 amd64 [installed]
行内信息解读:jammy,now 表示版本来自 jammy 套件且「now」是当前已装版本;方括号 [installed,automatic] 表示作为依赖自动装入(孤儿化后可被 autoremove),[installed] 表示手动安装。统计总量:
$ apt list --installed 2>/dev/null | wc -l
354
--upgradable 列出可升级包(本机全部为最新,输出只有 Listing... 表头):
$ apt list --upgradable
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Listing...
--manual-installed 只列手动安装的包(自动依赖被过滤,适合盘点「我到底装过什么」):
$ apt list --manual-installed | head -8
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Listing...
adduser/jammy,now 3.118ubuntu5 all [installed]
apt/jammy-updates,now 2.4.14 amd64 [installed]
base-files/jammy-updates,now 12ubuntu4.7 amd64 [installed]
base-passwd/jammy,now 3.5.52build1 amd64 [installed]
bash/jammy-updates,jammy-security,now 5.1-6ubuntu1.1 amd64 [installed]
bc/jammy,now 1.07.1-3build1 amd64 [installed]
bind9-host/jammy-security,now 1:9.18.39-0ubuntu0.22.04.7 amd64 [installed]
--all-versions 列出某包在缓存里的全部版本(本例仓库只有一个版本):
$ apt list --all-versions sl
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Listing...
sl/jammy 5.02-1 amd64
⚠️ 注意:
apt list在输出重定向时必定先打印 WARNING(Q1 详解),这也是官方暗示「脚本里别用 apt,用 apt-get」的信号之一。
💡 要点:三种清单各管一件事——
--installed盘点现状、--upgradable升级前巡检、--manual-installed导出装机清单(与 apt-mark showmanual 等价)。日常最实用的组合是apt list --upgradable先看名单、再决定apt upgrade还是逐包升级;--manual-installed输出适合存档比对两台服务器的装机差异。
3.12 upgrade 与 full-upgrade:升级的两种形态
两者都把已装包升级到候选版本,差异在是否允许为解决依赖而删除/新装包:upgrade 只升级、绝不动其他包(可能因此把部分包「保留」在旧版本);full-upgrade 允许删除/新装包以完成整体升级。用 -s 模拟对比(不实际改动系统):
$ apt list --upgradable
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
Listing...
$ apt-get -s upgrade
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
$ apt-get -s full-upgrade
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
本机全部包已是最新(apt list --upgradable 为空),两种模拟的结果一致。在有可升级包的真实场景中,二者汇总行的 N upgraded / M newly installed / K to remove 计数会出现差异:full-upgrade 的 to remove 可能大于 0(允许移除冲突包),upgrade 恒为 0(冲突包被 keep back)。日常巡检建议:先 apt update && apt list --upgradable 看清单,再决定 upgrade 还是 full-upgrade;涉及删除包的计划务必用 -s 预演后人工确认。
💡 要点:upgrade 输出里的
The following packages have been kept back是「有包需要连带删除/新装才能升级」的信号——看到它就说明这批包只有 full-upgrade 才能带上去。内核、glibc 这类强依赖包最常触发 kept back,升级前用apt -s full-upgrade看清楚到底会动哪些包。
3.13 -q:安静模式
-q(可叠加为 -qq)省略进度类输出,只保留结果行,适合记录日志。对比同一次 tree 安装,普通模式与 -q 模式的计划/下载/设置行完全一致(本环境输出本就精简,-q 主要在 TTY 进度条场景下起作用):
$ apt -q 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 (43.7 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 ... 26317 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
💡 要点:交互终端里 apt 有彩色高亮与动态进度条;重定向(管道/日志)时这些都被禁用,
-q面向的是进度指示而非结果行,判断成败仍以 rc 与 E:/W: 行为准。
3.14 下载缓存目录 /var/cache/apt/archives
下载的 .deb 与索引缓存分开存放:索引在 /var/lib/apt/lists/,.deb 在 /var/cache/apt/archives/。实测一个反直觉的事实——apt 2.4 在安装完成后默认不保留 .deb(自 apt 2.1.16 起 APT::Keep-Downloaded-Packages 默认关闭),缓存目录里只剩锁文件与临时目录:
$ ls -lh /var/cache/apt/archives/ | head -8
total 4.0K
-rw-r----- 1 root root 0 Sep 24 14:13 lock
drwx------ 1 _apt root 4.0K Oct 15 22:40 partial
$ du -sh /var/cache/apt/archives
20K /var/cache/apt/archives
lock 是并发互斥锁文件,partial/ 存放下载到一半的临时文件。只有 apt-get install -d(只下载不安装)等方式放入的 .deb 才会留存——完整的前后对照见姊妹篇 apt-get 篇的 clean/autoclean 实测。想改回「装完留包」的旧行为,可在 /etc/apt/apt.conf.d/ 下自建配置写 APT::Keep-Downloaded-Packages "true";。
💡 要点:apt 2.1.16+ 默认「装完即删 .deb」是为省磁盘,但离线分发、审计留包场景需要显式改回。清理磁盘时
apt clean/autoclean只清/var/cache/apt/archives/里的 .deb,不碰/var/lib/apt/lists/的索引缓存(后者用rm -rf /var/lib/apt/lists/*再apt update重建)。
3.15 edit-sources 与 --fix-broken
两个实用子命令/参数一句话带过:
apt edit-sources:用系统默认编辑器打开软件源配置(默认/etc/apt/sources.list),保存退出后 apt 自动做语法校验,改源比手改文件更安全。apt --fix-broken install(或apt install -f):修复依赖损坏的半安装态。典型触发场景是用 dpkg -i 装了缺依赖的 .deb;完整修复流程(构造 iU 状态 → 修复 → 验证)在 apt-get 篇-f/--fix-broken一节逐步实测,可直接照做。
💡 要点:
edit-sources的价值在「保存即校验」——手改 sources.list 敲错一个字,要到apt update才爆错且整个源不可用;edit-sources 在保存时当场拦住语法问题。--fix-broken则是 dpkg 半安装态的官方解药,与apt-get install -f完全等价,二者选顺手的即可。
3.16 退出码:仓库不存在的包返回 rc=100
包名在所有已配置源中都找不到时,apt 报 E 并以 100 退出(0 为成功,100 是 APT 家族约定俗成的「依赖/仓库类错误」):
$ apt install -y demo-not-exist; 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...
E: Unable to locate package demo-not-exist
rc=100
脚本中判断 apt 执行结果时,用 $? 是否为 0 即可覆盖绝大多数失败场景;遇到 100 先检查包名拼写与源配置(先 update 再确认)。
💡 要点:rc=100 的三大高发场景——包名拼错、刚改完源没
apt update、包只存在于别的 suite(如 backports)。处理口诀「先 update 刷索引 →apt-cache policy 包名查来源 → 再 install」,能消掉绝大多数 100;脚本里把 100 单独分流报警,比笼统的「非 0 即失败」定位快得多。
3.17 技术拓展:apt / apt-get / apt-cache 的分工对比
apt 家族命令常被混用,各自定位横向对比——
| 命令 | 定位 | 输出风格 | 适用场景 |
|---|---|---|---|
| apt | 交互式前端(合并最常用子命令) | 进度条 + 精简输出,CLI 不稳定(有 WARNING) | 管理员手工敲命令 |
| apt-get | 脚本化前端(最老牌) | 稳定、兼容性最好、rc 约定清晰 | 脚本/自动化/CI |
| apt-cache | 只读查询 | 纯文本结构化字段 | 不碰网络的包信息检索(search/show/madison) |
| apt-mark | 标记管理 | 简短回显 | auto/manual/hold 状态维护 |
| apt-file | 独立工具(需另装) | 路径列表 | 查「未安装的包提供哪个文件」 |
💡 关键差异一句话:apt 面向人、apt-get 面向脚本、apt-cache 面向查询。本文以 apt 为主线演示交互式用法(进度条友好),凡涉及自动化都在对应小节标注了 apt-get 等价写法(如
apt-get install -y),两个命令的子命令语义在 Ubuntu 22.04 上完全一致。
四、实战示例
4.1 新服务器软件初始化
刷新缓存 → 盘点可升级项 → 精简安装(不带推荐包):
apt update
apt list --upgradable
apt install -y --no-install-recommends tree sl
三步对应的真实回显形态分别见 3.1(Get/Hit 行)、3.11(Listing... 表头)与 3.3(1 newly installed 精简安装)。验收用 dpkg -l tree sl | grep '^ii'(回显见 3.2 末尾)。
4.2 查版本再精确安装
先 apt-cache madison 包名 拿到仓库真实版本号(回显见 3.5 第一步),再 apt show 包名 核对依赖与来源(回显见 3.10),最后按版本安装:
apt install -y sl=5.02-1
这套「先查后装」流程在需要固定版本的生产环境是标准动作,版本号必须与 madison/show 输出完全一致,否则 rc=100。
4.3 安装试用后的清理三连
试用 demo 包后的标准清理:remove 删程序 → autoremove --purge 清孤儿依赖及其配置 → dpkg -l 复查无残留:
apt remove -y demo-app
apt autoremove --purge -y
dpkg -l | grep demo-app || echo '无残留'
逐步回显与状态变化(ii→rc→消失)见 3.6/3.7/3.8,最后一条 grep 无输出即清理彻底。
4.4 脚本中安全使用 apt
自动化脚本里的推荐写法:-y 免交互、显式检查退出码、失败即中止:
apt update && apt install -y --no-install-recommends tree
rc=$?
if [ $rc -ne 0 ]; then echo "install failed rc=$rc"; exit 1; fi
&& 保证 update 失败不继续装;rc 判断覆盖 rc=100(找不到包)等错误。同时注意:apt 在输出重定向时会打印「无稳定 CLI 契约」的 WARNING(Q1),对输出格式有硬依赖的脚本建议改用 apt-get(回显对比见姊妹篇)。
五、注意事项与常见问题
Q1:为什么总是打印 WARNING: apt does not have a stable CLI interface. Use with caution in scripts.?
A:当 stdout 不是交互终端(管道、重定向、非 TTY)时,apt 会主动打印这条警告。官方 man 手册原文:The apt(8) commandline is designed as an end-user tool and it may change behavior between versions. While it tries not to break backward compatibility this is not guaranteed either if a change seems beneficial for interactive use.(apt 面向终端用户设计,行为可能在版本间变化;它尽量不破坏向后兼容,但若改动对交互使用有益,兼容性不获保证。)因此解析 apt 输出的自动化脚本存在升级后失效的风险,脚本场景应优先 apt-get。
Q2:apt 和 apt-get 到底什么关系? A:apt 是 apt-get + apt-cache 常用功能的整合壳,默认开启了几个更适合人的选项(如进度显示、upgrade 语义调整),底层与 apt-get 共用同一套缓存与求解器。功能上 apt 覆盖日常操作(update/install/remove/autoremove/upgrade/full-upgrade/search/show/list/edit-sources);apt-get 则提供更多低频但稳定的子命令(-d 只下载、-s 模拟、-f 修复、clean/autoclean、check、changelog、download 等),且输出契约稳定。经验法则:手敲用 apt,写脚本用 apt-get,查信息用 apt-cache。
Q3:装完包后 /var/cache/apt/archives 里怎么没有 .deb?
A:apt 2.1.16 起默认不在安装后保留下载的 .deb(APT::Keep-Downloaded-Packages 默认关闭),实测缓存目录只剩 lock 与 partial/(回显见 3.14)。需要保留时用 apt-get install -d 只下载,或把该选项显式置为 true。
Q4:apt update 出现 W: Failed to fetch 但退出码是 0?
A:实测单个源失败(如域名不可解析)只产生 Err: 与 W: 警告,rc 仍为 0(回显见 3.1 第三块);apt 的设计是「失败源用旧缓存顶着」。因此脚本里不能只看 update 的 rc,要确认关键源没有 Err/W 行;而后续 install 若依赖缺失会以 rc=100 真实报错。
Q5:remove 之后 dpkg -l 包名 报 no packages found,配置不还在吗?
A:rc 残留状态只为「带 conffile 的包」而存在。像 cowsay 这类没有 conffile 的包,remove 后即从 dpkg 数据库消失;只有自带配置文件的包才走 ii→rc→purge 的三段过程(实测对照见 3.6/3.7 的 demo-app)。判断某包是否带 conffile,可查 apt show 包名 对应的包描述或 dpkg -L 包名 中 /etc 下的文件。
Q6:对已安装的包再执行 install 会怎样? A:什么都不装,提示已最新并 rc=0。实测还原 zip/unzip 时的真实回显:
$ apt install -y zip unzip; 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...
zip is already the newest version (3.0-12build2).
The following NEW packages will be installed:
unzip
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 175 kB of archives.
After this operation, 386 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 unzip amd64 6.0-26ubuntu3.2 [175 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 175 kB in 2s (91.3 kB/s)
Selecting previously unselected package unzip.
(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 ... 26294 files and directories currently installed.)
Preparing to unpack .../unzip_6.0-26ubuntu3.2_amd64.deb ...
Unpacking unzip (6.0-26ubuntu3.2) ...
Setting up unzip (6.0-26ubuntu3.2) ...
rc=0
同一命令按包分别判断:zip 已最新(跳过),unzip 未装(安装)。要强制覆盖已装文件用 --reinstall(见 3.4)。
Q7:构建带配置文件的 .deb 时报 conffile name is not an absolute pathname?
A:dpkg 1.21.1 起 DEBIAN/conffiles 清单必须写绝对路径。实测错误:写 etc/demo-app/demo.conf 时 dpkg-deb --build 报 dpkg-deb: error: conffile name 'etc/demo-app/demo.conf' is not an absolute pathname(rc=2);改成 /etc/demo-app/demo.conf 后构建成功(回显见 3.6)。
Q8:能直接把 apt 用于生产变更吗?
A:可以,但建议遵守三件事:变更前 apt update 刷新缓存;大变更(升级/批量装删)先 -s 模拟或 apt list --upgradable 预览;所有非交互调用带 -y 并检查 rc。apt 无稳定输出契约(Q1),CI 流水线里优先 apt-get。
六、参考链接
- apt(8) 手册(Ubuntu 22.04 jammy 版):https://manpages.ubuntu.com/manpages/jammy/en/man8/apt.8.html
- apt-get(8) 手册:https://manpages.ubuntu.com/manpages/jammy/en/man8/apt-get.8.html
- sources.list(5) 软件源配置:https://manpages.ubuntu.com/manpages/jammy/en/man5/sources.list.5.html
- apt_preferences(5) 版本优先级:https://manpages.ubuntu.com/manpages/jammy/en/man5/apt_preferences.5.html
- apt-secure(8) 签名校验:https://manpages.ubuntu.com/manpages/jammy/en/man8/apt-secure.8.html
- Debian Wiki AptCLI(apt 与 apt-get 的关系):https://wiki.debian.org/AptCLI
- Ubuntu 官方包管理文档:https://ubuntu.com/server/docs/package-management