本文要点
- Ubuntu 的软件包体系分两层:底层
dpkg直接操作.deb包,上层apt负责依赖解析与软件源管理,日常操作基本都用apt - Ubuntu 24.04 的软件源采用 deb822 格式(
/etc/apt/sources.list.d/ubuntu.sources),结构更清晰;老格式sources.list仍然兼容 apt update刷新软件源索引,apt upgrade升级已装包,两者顺序不能颠倒;升级前建议先apt list --upgradable预览- 卸载分两级:
apt remove保留配置文件,apt purge连配置一起删除;apt autoremove清理无用依赖 dpkg -l / -s / -S / -L分别查询已装列表、包状态、文件归属、包内文件清单;本文命令均在 Ubuntu 24.04 上真实执行验证
apt 与 dpkg:两层包管理
大多数 Linux 用户对 Ubuntu 的印象是从「双击安装包」或「一行命令装软件」开始的,而这两件事背后是两套分工明确的工具:
- dpkg:Debian 系最底层的包管理器,直接操作
deb包文件,负责安装、卸载、查询。但它不处理依赖关系——装 A 需要 B 时,它不会自动帮你把 B 一起装上。 - apt:构建在 dpkg 之上的高级工具。它读取软件源索引,解析依赖树,把「要装一个软件」翻译成「要装这一组 deb 包」,再交给 dpkg 落地执行。
用一句话概括:apt 管「要装什么」,dpkg 管「怎么装」。 日常运维 90% 的操作发生在 apt 这一层,但排查问题时经常要下钻到 dpkg——这也是这篇文章把两层都讲清楚的原因。
apt 的完整文档可参考 Ubuntu 官方 Apt 文档。
软件源:包从哪来
apt 安装的软件来自「软件源(repository)」。Ubuntu 把官方软件源按「套件(Suite)× 组件(Component)」切成网格,软件源配置就是告诉 apt 去哪里、拉哪些网格。
deb822 格式:Ubuntu 24.04 的默认配置
从 Ubuntu 22.04 起,系统默认使用 deb822 格式管理软件源,配置文件在 /etc/apt/sources.list.d/ubuntu.sources。下面这张图是在演示服务器(Ubuntu 24.04)上执行 grep 过滤掉注释后的真实内容:

图中每一条「源」由几个字段组成,含义如下:
Types:包类型。deb是二进制包,如需下载源码包则追加deb-src。URIs:仓库服务器地址,本机是archive.ubuntu.com(主源)和security.ubuntu.com(安全更新源)。Suites:套件名。Ubuntu 24.04 代号noble,noble是正式发布版,noble-updates是修复补丁,noble-backports是向后移植的新版软件。Components:组件。main(官方维护、完全免费)、universe(社区维护)、restricted(含专有驱动)、multiverse(法律受限软件)。Signed-By:仓库签名公钥,apt 用它校验下载的包是否被篡改。
图中下方的 apt-cache policy 输出则展示了 apt 对每个源的「优先级」:数字越大优先级越高,500 是常规源,100 是本机已装状态。多个源提供同一软件时,apt 会优先用优先级高的版本。
deb822 的完整字段说明可参考 sources.list(5) 手册页。
老式 sources.list 格式
如果你看到的还是 /etc/apt/sources.list 单行格式,那也一样有效:
deb http://archive.ubuntu.com/ubuntu noble main universe restricted multiverse
deb-src http://archive.ubuntu.com/ubuntu noble main universe restricted multiverse每行开头是 deb(或 deb-src),中间是仓库地址,后面依次是发行版代号和组件列表。deb822 格式本质上就是这种单行格式的「结构化拆解」,两者可以共存。
手动增删软件源
需要添加第三方源时,推荐的做法是单独建文件、单独配签名,这样卸载时删除对应文件即可,互不干扰:
# 添加 GitHub CLI 官方源(示例)
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt updateapt update / upgrade:更新系统
新装或修改软件源后,第一件事是 apt update——它从所有已配置的源拉取最新的包索引:
sudo apt update看到 Reading package lists... Done 以及最后的 All packages are up to date(或可升级数量),说明索引刷新成功。注意:update 只是更新索引,并不会升级任何软件。
真正升级已装包的是 apt upgrade。升级前建议先预览有哪些可升级:
apt list --upgradable
sudo apt upgrade几点实用经验:
- 先 update 再 upgrade:索引没刷新就 upgrade,装的是旧索引里的旧版本,等于白做。
- 升级内核:
apt upgrade升级内核后,需要重启系统新内核才生效,可用uname -r确认当前内核版本。 - 只升级安全更新:如果不想被普通更新打扰,可以用
sudo apt update && sudo apt upgrade --only-upgrade配合套件筛选,或直接用unattended-upgrades做全自动安全更新。
apt install:安装与依赖解析
安装软件是 apt 最常见的用法。下图是演示服务器上 apt-get install -y tree 的真实执行过程(tree 是一个以树状图显示目录结构的工具):

安装输出的关键行值得逐条读一遍:
Reading package lists...→Building dependency tree...:apt 读取索引、构建依赖树,这是「自动解析依赖」的开始。The following NEW packages will be installed: tree:apt 告诉你本次要装的包列表。没有依赖要额外安装时,列表只有它一个。0 upgraded, 1 newly installed, 0 to remove and 5 not upgraded.:升级 0 个、新装 1 个、移除 0 个;末尾的5 not upgraded表示还有 5 个包因依赖等原因暂未升级。Preparing to unpack/Unpacking tree ...:dpkg 层面开始解包。Setting up tree ...:解包完成后的配置阶段,此时软件才真正可用。Processing triggers for man-db ...:处理触发器,如刷新 man 手册索引。
如果某个软件依赖了多个包,你会看到列表变成好几行,apt 会一次性把依赖全部装好,这正是它比 dpkg 好用的地方。
# 同时安装多个包
sudo apt install htop curl jq
# 只下载不安装(-d = download)
sudo apt install -d htop
# 重新配置已安装包的配置向导
sudo dpkg-reconfigure tzdata卸载与清理
卸载同样走 apt 这一层,但要知道「删配置」和「删干净」是两件事:
# 卸载软件,保留配置文件(重新安装时配置还在)
sudo apt remove tree
# 卸载并连配置文件一起删除
sudo apt purge tree
# 清理因依赖装上来、现在没用的软件包
sudo apt autoremove
# 清理下载缓存(/var/cache/apt/archives)
sudo apt clean什么时候用 purge? 卸载服务类软件(nginx、mysql 等)后,它们通常会把配置和数据留在 /etc、/var 下,重装时可能读到旧配置导致「装了等于没装」。此时用 purge 更干净。只卸工具类软件用 remove 即可。
apt 查询:装之前先看看
安装前用 apt-cache 系列命令侦察一下,能避免很多「装错版本」的问题:
# 搜索软件包
apt-cache search "pdf 编辑器"
# 查看包详情:版本、依赖、大小、描述
apt-cache show htop
# 查看安装/候选版本与优先级
apt-cache policy htop
# 查看某个包依赖什么
apt-cache depends htopapt-cache policy 输出里两个数字最关键:Installed(已装版本)和 Candidate(可升级到的版本)。候选版本往往决定着你能不能用上某个新功能。
dpkg:包管理的「底层机关」
apt 只管上层编排,真正的安装、查询、卸载动作都落在 dpkg 上。当需要精确控制单个 deb 包时,直接操作 dpkg 更顺手。下图是在演示服务器上对 tree 做的三种查询:

逐条解释图中命令:
dpkg -s tree(query status):显示包的状态与元信息。Status: install ok installed里三段分别表示「期望状态=已安装」「实际状态=正常」「错误=无」。Installed-Size: 108是占用磁盘大小(KB),Version是当前版本号。dpkg -S /usr/bin/tree(search):反查「某个文件属于哪个包」,排查「这个文件是哪来的」时非常有用。dpkg -L tree(list files):列出包安装后包含了哪些文件,包括二进制、文档和 man 手册。看到/usr/share/man/man1/tree.1.gz就能确认手册页已就位。
其他高频 dpkg 命令:
# 查看已安装的所有包(-l = list),管道 grep 按名筛选
dpkg -l | grep htop
# 列出某个包的版本与状态简表
dpkg -l htop
# 安装本地 .deb 文件(不解析依赖,需自行保证依赖已装)
sudo dpkg -i 某软件.deb
# 卸载本地安装的包
sudo dpkg -r 包名
# 检查包是否完好(校验文件完整性)
sudo dpkg -V 包名注意 dpkg -i 不处理依赖——直接装一个带依赖的 .deb 会报依赖缺失。想用本地 .deb 又不想手动装依赖,可以先 sudo dpkg -i 文件.deb 再用 sudo apt -f install 让 apt 补齐缺失的依赖。
常用组合与排查技巧
把 apt 和 dpkg 串起来,能解决绝大多数包管理问题:
# 1. 依赖损坏修复:装一半断了,用 -f 修复
sudo apt -f install
# 2. 锁定版本:防止某个包被 upgrade 误升级
sudo apt-mark hold nginx
apt-mark showhold # 查看被锁定的包
sudo apt-mark unhold nginx # 解除锁定
# 3. 列出某个已装包的确切版本
dpkg-query -W -f='${Version}\n' nginx
# 4. 查看 apt 操作历史日志
grep -E "^(Start|Commandline|Install|Remove|Upgrade)" /var/log/apt/history.log常见故障定位顺序:先 apt update 看索引是否正常 → 报依赖错误就 apt -f install → 还不行就 apt-cache policy 包名 看版本来源 → 最后用 dpkg -l 包名 确认实际状态。绝大多数「装不上」的问题都能在这个循环里解决。
总结
Ubuntu 的包管理是一套清晰的上下层协作:apt 负责软件源与依赖解析,dpkg 负责对 deb 包的落地操作。日常用 apt update/install/remove/upgrade 四个命令就能覆盖大部分场景,遇到依赖或本地 deb 包问题再下钻到 dpkg -i/-r/-l/-S/-L。掌握这套体系,就掌握了 Ubuntu 运维的最基础也是最常用的一环。
更多细节可参考 Ubuntu 官方软件包管理文档 与 dpkg(1) 手册页。
评论 (0)
暂无评论,快来抢沙发吧!