apt-mark 命令详解与参数实测(Ubuntu 22.04)

apt-mark 命令详解:在 Ubuntu 22.04(apt 2.4.14)环境逐参数实测 auto/manual 安装标记、hold/unhold 版本锁定、showauto/showmanual/showhold 状态查询与 minimize-manual 清单瘦身,含 extended_states 机制解析、dpkg --get-selections 对照验证、手工清单导出恢复等实战场景与踩坑记录。

Linux命令Linux系统UbuntuUbuntu 22.04命令行包管理2026/10/16

apt-mark 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 apt-mark 的每一个常用参数——auto/manual 安装标记、hold/unhold 版本锁定、showauto/showmanual/showhold 状态查询与 minimize-manual 清单瘦身,全部命令与回显已在 Ubuntu 22.04(apt 2.4.14)实测通过。

一、环境信息

本篇所有命令均在以下环境中逐条真实执行,回显为实际输出(非编造):

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64),内核 6.8.0-138-generic
  • apt / apt-mark 版本:apt 2.4.14 (amd64)
  • dpkg 版本:Debian 'dpkg' package management program version 1.21.1 (amd64).
  • 软件源:Ubuntu 官方 archive 源,可正常联网更新
  • 测试数据包:cowsay 3.03+dfsg2-8(依赖 libtext-charwidth-perl 0.04-10build3),可执行程序安装到 /usr/games/cowsay
  • 标记数据落盘位置(实测确认存在):
    • 手工/自动安装标记:/var/lib/apt/extended_states
    • hold 锁定状态:dpkg 选中状态(可通过 dpkg --get-selections 读取,底层记录在 /var/lib/dpkg/status 的 want 字段)

二、命令概览

2.1 语法与测试数据

apt-mark 是 apt 家族中专门管理「包标记」的工具,不安装、不卸载任何软件,只修改两类元数据:安装方式标记(手工 manual / 自动 auto) 与 版本锁定状态(hold)。

apt-mark [选项] {auto|manual} 包名 [包名...]     # 修改安装方式标记
apt-mark [选项] {hold|unhold} 包名 [包名...]     # 修改版本锁定状态
apt-mark [选项] {showauto|showmanual|showhold}   # 列出对应标记的包

常用子命令一览:

子命令作用本文实测
auto把包标记为自动安装是(3.4 节)
manual把包标记为手工安装是(3.5 节)
hold锁定包版本,禁止被升级是(3.6 节)
unhold解除版本锁定是(3.7 节)
showauto列出所有自动安装的包是(3.2 节)
showmanual列出所有手工安装的包是(3.1 节)
showhold列出所有被锁定的包是(3.3 节)
minimize-manual把元包依赖批量转为自动标记(危险)是(3.8 节,仅 --dry-run)

关键差异/如何读这张表:show* 三个子命令是只读查询,任何环境都可以放心执行;auto/manual/hold/unhold 是写操作,只改标记不动文件;minimize-manual 会大面积改写手工标记,只建议带 --dry-run 演练。

💡 技术拓展:Debian 系包管理有两套「状态账本」,apt-mark 恰好横跨两者——

账本存储文件记录内容由谁写入
apt 扩展状态/var/lib/apt/extended_states手工/自动(Auto-Installed: 1)标记apt、apt-mark
dpkg 选中状态/var/lib/dpkg/status(want 字段)install / hold / deinstall / purgedpkg、apt-mark

auto/manual 标记决定 apt-get autoremove 的回收范围;hold 锁定写入 dpkg 选中状态,所以能被 dpkg --get-selections 读到。两套账本各管一事、互不替代。

测试数据包说明:选用体积小、依赖浅的 cowsay(一头会说话的牛,输出 ASCII 图画)作为演示对象,安装后位于 /usr/games/cowsay。每个演示块自带安装与清理,保证可重复执行。

2.2 --help 全量输出(逐行照抄)

$ apt-mark --help
apt 2.4.14 (amd64)
Usage: apt-mark [options] {auto|manual} pkg1 [pkg2 ...]

apt-mark is a simple command line interface for marking packages
as manually or automatically installed. It can also be used to
manipulate the dpkg(1) selection states of packages, and to list
all packages with or without a certain marking.

Most used commands:
  auto - Mark the given packages as automatically installed
  manual - Mark the given packages as manually installed
  minimize-manual - Mark all dependencies of meta packages as automatically installed.
  hold - Mark a package as held back
  unhold - Unset a package set as held back
  showauto - Print the list of automatically installed packages
  showmanual - Print the list of manually installed packages
  showhold - Print the list of packages on hold

See apt-mark(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).

帮助信息共列出 8 个子命令,与 2.1 节表格一一对应。注意 Usage 行只写了 {auto|manual},实际 hold/unhold/show* 同样以「子命令 + 包名」的形式使用。

2.3 版本信息

$ apt-mark --version
apt 2.4.14 (amd64)

apt-mark 没有独立的版本号,随 apt 一起发布。Ubuntu 22.04 官方源的 apt 为 2.4.x 系列,本文实测值为 2.4.14。查版本时可直接用 apt --version,结果一致。

三、参数逐项实测

3.1 showmanual:列出手工安装的包

「手工安装」指被管理员显式指定安装的包。查询是只读操作,先看列表头部与总数:

$ apt-mark showmanual | head -8
adduser
apt
base-files
base-passwd
bash
bc
bind9-host
binutils

$ apt-mark showmanual | wc -l
143

当前环境共 143 个手工安装包,多为系统基础组件(bash、apt 等)——它们在系统初始化时被标记为手工安装。

💡 要点:showmanual 的典型用途是导出装机清单。把它重定向到文件保存,迁移或重建环境时可用 xargs apt-mark manual < 清单文件 整批恢复标记(见 4.1 节实测)。

3.2 showauto:列出自动安装的包

「自动安装」指仅因满足依赖而被带进来的包。这类包一旦不再被任何手工安装包依赖,就会成为 apt-get autoremove 的回收对象:

$ apt-mark showauto | head -8
apparmor
bind9-dnsutils
bind9-libs
binutils-common
binutils-x86-64-linux-gnu
build-essential
ca-certificates
cpp

$ apt-mark showauto | wc -l
210

自动安装包共 210 个,明显多于手工包——这正是 Debian 系「依赖自动管理」设计的表现:管理员只声明需要什么,依赖关系由 apt 维护。

💡 要点:showauto 是执行 apt-get autoremove 之前的安全检查清单——先看一眼会被回收的名单,再决定是否加 -y。

3.3 showhold:列出被锁定的包

$ apt-mark showhold

$ apt-mark showhold; echo rc=$?
rc=0

没有锁定任何包时,输出为空、退出码为 0。showhold 是升级前巡检的常用命令——升级失败后第一件事就是确认是否有历史遗留的 hold。

💡 要点:空输出本身就是有效巡检结论——「当前无版本锁定」,可放心执行批量升级。把它写进升级前检查清单(apt-mark showhold、apt list --upgradable、df -h / 三连),能提前排掉大半「升级不上也不下」的疑难。

3.4 auto:把包标记为自动安装

修改标记不会立刻删除任何文件,但会改变 autoremove 的回收范围。完整链路实测:安装 cowsay → 显式安装自动带上了手工标记 → 改标 auto → 被 autoremove 回收:

$ DEBIAN_FRONTEND=noninteractive apt-get install -y -qq -o Dpkg::Use-Pty=0 cowsay; echo rc=$?
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libtext-charwidth-perl.
(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

$ /usr/games/cowsay hello
 _______
< hello >
 -------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

$ apt-mark showmanual | grep cowsay
cowsay

$ apt-mark auto cowsay; echo rc=$?
cowsay set to automatically installed.
rc=0

$ apt-mark showauto | grep cowsay
cowsay

$ apt-mark showmanual | grep cowsay; echo rc=$?
rc=1

$ apt-get autoremove -y -o Dpkg::Use-Pty=0 2>&1 | tail -8
Reading state information...
The following packages will be REMOVED:
  cowsay libtext-charwidth-perl
0 upgraded, 0 newly installed, 2 to remove and 0 not upgraded.
After this operation, 139 kB disk space will be freed.
(Reading database ... 26390 files and directories currently installed.)
Removing cowsay (3.03+dfsg2-8) ...
Removing libtext-charwidth-perl (0.04-10build3) ...

$ which cowsay; echo rc=$?
rc=1

验证闭环:apt-mark auto cowsay 返回 cowsay set to automatically installed.,showauto 中出现、showmanual 中消失(grep 无命中,rc=1);随后 apt-get autoremove 把 cowsay 连同其专属依赖 libtext-charwidth-perl 一并回收,which cowsay 已找不到命令(rc=1)。

💡 要点:auto 标记的真正威力在「连带回收」——cowsay 被回收的同时,只为它服务的依赖也被清掉,这正是生产环境清理实验包的标准姿势。

3.5 manual:把包标记为手工安装

反向操作。先把 cowsay 标成 auto,再用 manual 改回,验证 autoremove 不再动它:

$ DEBIAN_FRONTEND=noninteractive apt-get install -y -qq -o Dpkg::Use-Pty=0 cowsay; echo rc=$?
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libtext-charwidth-perl.
(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-mark auto cowsay; echo rc=$?
cowsay set to automatically installed.
rc=0

$ apt-mark showauto | grep cowsay
cowsay

$ apt-mark manual cowsay; echo rc=$?
cowsay set to manually installed.
rc=0

$ apt-mark showmanual | grep cowsay
cowsay

$ apt-get autoremove -y -o Dpkg::Use-Pty=0 2>&1 | tail -2
Reading state information...
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

验证闭环:改回 manual 后,showmanual 能查到 cowsay,且 apt-get autoremove 输出 0 to remove——手工包受保护,不会被自动回收。

💡 要点:对「实际是依赖、但业务上必须保留」的包(例如某个被 apt 想回收的底层库),apt-mark manual 是最快的保命符。

3.6 hold:锁定包版本

hold 把包的「选中状态」改写为 hold,apt 在升级计算时会跳过它。实测:

$ apt-mark hold cowsay; echo rc=$?
cowsay set on hold.
rc=0

$ apt-mark showhold
cowsay

$ dpkg --get-selections cowsay
cowsay						hold

机制说明:apt-mark hold 本质是改写 dpkg 选中状态(want 字段)为 hold。此后:

  1. apt-get upgrade / apt upgrade 计算可升级集合时会跳过被 hold 的包,它们不会出现在升级清单中(体现为 kept back,不升级);
  2. 即便执行 apt-get upgrade 包名 显式升级,apt 也会提示该包处于 hold 状态而拒绝动作;
  3. 锁定是持久的,重启、apt update 都不会解除,必须显式 unhold。

本环境当前没有待升级的包(apt list --upgradable 仅输出 Listing... 一行),因此「升级清单跳过」未在本环境触发,效果通过 showhold 列表与 dpkg --get-selections 显示的 hold 状态共同验证——这也是生产上最快的两个核对点。

💡 技术拓展:在 Ubuntu 上「锁版本」不止 hold 一条路——

方式命令形态特点适用场景
apt-mark holdapt-mark hold cowsay状态持久、可 showhold 查询、unhold 一键解除临时冻结个别包,最常用
apt 钉扎 pinning/etc/apt/preferences 写 Pin-Priority可按版本/来源精细钉扎长期固定某源或某版本线
指定版本安装apt install cowsay=3.03+dfsg2-8一次性、无持久约束偶尔降级
dpkg 选中状态echo "cowsay hold" | dpkg --set-selections与 hold 等效的老式写法兼容老脚本

本文采用 apt-mark hold/unhold:语义直白、有 showhold 巡检命令配套,且与 dpkg --get-selections 可互相印证。

3.7 unhold:解除版本锁定

$ apt-mark unhold cowsay; echo rc=$?
Canceled hold on cowsay.
rc=0

$ dpkg --get-selections cowsay
cowsay						install

$ apt-mark showhold; echo rc=$?
rc=0

验证闭环:unhold 返回 Canceled hold on cowsay.,dpkg --get-selections 的状态从 hold 恢复为 install,showhold 再次为空。hold/unhold 一对操作状态迁移清晰可查。

💡 要点:解除锁定后该包立即回到升级候选队列,下次 apt upgrade 就可能被升上去——unhold 不是「恢复原状」而是「放行」。生产上解除冻结前先看一眼 apt list --upgradable <包名>,确认目标版本符合预期再放行,避免冻结束就被动升到大版本。

3.8 minimize-manual:手工安装清单瘦身(危险)

minimize-manual 会扫描所有手工包,把「实际被元包/其他包依赖」的部分批量改为自动标记,用于精简装机清单。因为影响面大,帮助信息中标注了 DANGEROUS 语义,官方推荐先 --dry-run 演练:

$ apt-mark minimize-manual --dry-run; echo rc=$?
No changes necessary
rc=0

当前环境手工包清单已是「最小集」,演练输出 No changes necessary。若系统里装过 tasksel/元包类组合,这里会列出一长串将被改标为 auto 的包名。

⚠️ 拼写踩坑(实测):英式拼写 minimise-manual 不被识别,且报错信息容易误导——

$ apt-mark minimise-manual --dry-run 2>&1; echo rc=$?
E: Command line option --dry-run is not understood in combination with the other options
rc=100

报错说的是 --dry-run 选项,真正原因是第一个词 minimise-manual 没有被认作子命令。请使用美式拼写 minimize-manual。

💡 要点:--dry-run 是这条危险命令唯一推荐的使用方式——真实执行会把大批手工包改成 auto,下一次 apt-get autoremove 可能连带卸载桌面环境、编译工具链等「看似只是依赖」的组件。生产上遵循「先 dry-run 留档 → 人工审阅名单 → 确认后再真跑」三步,且真跑后立刻执行一次不带 -y 的 apt-get autoremove 复核回收名单。

3.9 show:不存在的子命令(踩坑)

直觉上容易把三个查询子命令缩写成 show,实测会直接报错:

$ apt-mark show 2>&1; echo rc=$?
E: Invalid operation show
rc=100

E: Invalid operation show、退出码 100。apt 系命令的操作类错误统一返回 100,脚本中可用 rc -eq 100 识别「子命令写错」。查询必须写全:showauto / showmanual / showhold。

💡 要点:apt 家族(apt / apt-get / apt-cache / apt-mark)对「不存在的子命令」一律回 E: Invalid operation <词> + rc=100,且不给出「你是不是想输入 XX」的提示——拼写错误只能靠人工发现。巡检脚本里对 apt 系命令统一检查 rc -eq 100 分支,能把拼写类故障在第一时间拦截。

四、实战示例

4.1 导出并恢复手工安装清单

场景:装机配置完成后留存「管理员显式装了什么」的清单,重建环境时整批恢复。

$ apt-mark showmanual > /tmp/manual-list.txt; wc -l /tmp/manual-list.txt
144 /tmp/manual-list.txt

$ apt-mark auto cowsay; echo rc=$?
cowsay set to automatically installed.
rc=0

$ apt-mark showmanual | grep cowsay; echo rc=$?
rc=1

$ xargs apt-mark manual < /tmp/manual-list.txt 2>&1 | tail -3
zip was already set to manually installed.
zlib1g was already set to manually installed.
cowsay set to manually installed.

$ apt-mark showmanual | grep cowsay
cowsay

$ apt-get autoremove -y -o Dpkg::Use-Pty=0 2>&1 | tail -2
Reading state information...
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

解读:清单共 144 行(此时 cowsay 在清单内)。把 cowsay 改成 auto 模拟「标记丢失」,xargs apt-mark manual < 清单 整批回灌——已处于手工状态的包输出 was already set to manually installed.(幂等,无副作用),丢失标记的 cowsay 被重新标记。最后 autoremove 显示 0 to remove,确认恢复生效。

4.2 升级窗口期锁定关键组件

场景:维护窗口只想升级安全补丁,暂缓某核心组件(以 bash 为例),升级结束再放开。

$ apt-mark hold bash; echo rc=$?
bash set on hold.
rc=0

$ apt-mark showhold
bash

$ dpkg --get-selections bash
bash						hold

$ apt-mark unhold bash; echo rc=$?
Canceled hold on bash.
rc=0

$ dpkg --get-selections bash
bash						install

$ apt-mark showhold; echo rc=$?
rc=0

解读:hold → showhold 确认在列 → dpkg --get-selections 交叉核对状态为 hold → 升级窗口结束 unhold → 状态回到 install → showhold 清空。两个查询命令形成双确认,避免「以为锁了/以为解了」的单点误判。

4.3 三种标记状态一键核对

场景:接手一台陌生服务器,判断某包当前的标记状态(以 cowsay 处于 auto + hold 复合状态为例):

$ apt-mark showmanual | grep cowsay; echo rc=$?
rc=1

$ apt-mark showauto | grep cowsay
cowsay

$ apt-mark showhold | grep cowsay
cowsay

解读:三条 grep 三连——showmanual 无命中(rc=1)说明不是手工安装,showauto 命中说明是自动安装,showhold 命中说明还被锁定了版本。auto 与 hold 可同时成立:前者属于 apt 的扩展状态,后者属于 dpkg 选中状态,互不冲突。

4.4 标记机制的底层证据

场景:验证 2.1 节「两套账本」的说法,直接看标记落盘文件:

$ apt-mark showmanual | wc -l; apt-mark showauto | wc -l; apt-mark showhold | wc -l
143
210
0

$ ls -l /var/lib/apt/extended_states
-rw-r--r-- 1 root root 12750 Oct 15 22:35 /var/lib/apt/extended_states

$ grep -c "Auto-Installed: 1" /var/lib/apt/extended_states
212

$ head -4 /var/lib/apt/extended_states
Package: libxtables12
Architecture: amd64
Auto-Installed: 1

解读:extended_states 是纯文本,按「Package/Architecture/Auto-Installed」三元组记录。文件内 Auto-Installed: 1 共 212 条,而 showauto 实时输出 210 个——差值来自历史残留记录:extended_states 中个别条目对应的包已不在当前 auto 集合(如已被回收或改标),showauto 以「当前已安装 + 标记」为准做实时过滤。这也是为什么不建议手工编辑该文件,统一用 apt-mark 操作。

五、注意事项与常见问题

Q1:为什么 apt-mark show 会报错? apt-mark 没有 show 子命令,只有 showauto/showmanual/showhold 三个查询命令,且报错为 E: Invalid operation show(退出码 100)。apt 系命令约定俗成:语法/操作错误返回 100,可用于脚本判错。

Q2:apt-mark auto 包名 会马上删掉这个包吗? 不会。auto 只修改标记,不动文件;实际删除发生在下一次 apt-get autoremove,且仅当该包不再被任何手工包依赖时才回收。3.4 节实测了完整链路:auto 之后 cowsay 仍可运行,autoremove 之后才消失。

Q3:hold 之后,apt upgrade 就绝对碰不到这个包了吗? 常规升级不会:apt 计算升级集时跳过 hold 状态的包,包会以 kept back 形态留在原地。但要注意两点例外——显式 apt-get install 包名 并确认覆盖提示,或卸载重装(purge 后重装会重置选中状态)。所以关键包的 hold 应纳入巡检:apt-mark showhold 与 dpkg --get-selections 包名 双核对。

Q4:误把一大批包标成了 auto,眼看要被 autoremove 回收,怎么救? 立即执行 apt-get autoremove 前打断(autoremove 有确认步骤,不加 -y 不会真删);然后按 4.1 节方式用之前导出的手工清单回灌:xargs apt-mark manual < /tmp/manual-list.txt。没导出过清单时,可从 showauto 反查、或用安装历史 /var/log/apt/history.log 逐条找回。这也是「装完机先导出 showmanual」的价值所在。

Q5:cowsay 装完敲 cowsay 提示找不到命令? Ubuntu 将游戏/趣味类程序装到 /usr/games,该目录不在默认 PATH 中,实测需全路径执行 /usr/games/cowsay hello。用 dpkg -L cowsay | grep bin 可查到实际安装路径。

Q6:脚本里执行 apt-get 安装时,回显出现 (Reading database ... 5%(... 一路刷屏怎么办? 这是无终端环境下 dpkg 进度回显被拼接所致。给 apt-get 加 -o Dpkg::Use-Pty=0 即可获得干净输出(本文所有安装回显均如此处理),日志更适合归档阅读。

Q7:apt-mark 的修改需要重启什么服务/进程生效吗? 不需要。apt-mark 是一次性命令行工具,直接读写状态文件,没有守护进程;修改即时生效,下一条 apt 命令即按新标记决策。

六、参考链接