在Debian系统运维中,想要查看哪些软件包是用户手动安装的(而非系统依赖自动拉取的),最直接有效的命令就是apt-mark showmanual。这个命令会列出所有被标记为"手动安装"的软件包,是排查系统臃肿、清理无用包、做系统迁移或备份时的核心工具。很多运维人员只会用apt list --installed查看已安装包,但那个列表包含了大量依赖包,根本无法区分哪些是你主动装的、哪些是被自动拖进来的,而apt-mark showmanual正好解决了这个痛点。

apt-mark showmanual的基本用法和输出解读

直接在终端输入以下命令即可查看所有用户手动安装的包:

apt-mark showmanual

输出结果类似这样:

nginx
curl
vim
htop
python3-pip
...

每一行就是一个被标记为手动安装的软件包名称。这个列表通常比apt list --installed的输出短得多,因为它过滤掉了所有作为依赖被自动安装的包。比如你装了一个nginx,系统会自动拉取几十个依赖库,但apt-mark showmanual只会显示nginx本身。

如果你想查看某个特定包是否是手动安装的,可以加上包名过滤:

apt-mark showmanual | grep nginx

有输出就说明是手动装的,没有输出则说明它是作为依赖被自动安装进来的。

为什么需要区分手动安装包和自动依赖包

在Debian的apt包管理体系中,每个软件包都有一个"安装状态标记"。当你执行apt install xxx时,apt会把xxx标记为"manual"(手动安装),同时把它依赖的所有包标记为"auto"(自动安装)。这个机制的设计初衷是:当你卸载一个手动安装的包时,如果它的依赖包没有其他手动安装的包需要,那些依赖包也会被自动清理掉,从而保持系统干净。

但实际运维中问题来了。时间久了,你可能装了又卸、卸了又装,系统里会残留大量标记为auto但实际上已经没人用的依赖包。或者你想把当前服务器的"核心软件清单"导出来,方便在新机器上快速复现环境,这时候就需要apt-mark showmanual给你一个干净的、只包含用户主动选择的包列表。

apt-mark的完整命令体系

apt-mark其实是一个包标记管理工具,它有多个子命令,showmanual只是其中之一。完整的命令体系包括:

apt-mark showmanual      # 查看手动安装的包
apt-mark showauto        # 查看自动安装的包(即依赖包)
apt-mark hold 包名        # 锁定某个包,阻止它被自动升级或卸载
apt-mark unhold 包名      # 解除锁定
apt-mark manual 包名      # 手动将某个包标记为手动安装
apt-mark auto 包名        # 将某个包标记为自动安装

其中apt-mark manualapt-mark auto在实际运维中非常有用。比如你发现某个依赖包被意外标记成了manual(可能是你不小心用apt install装了它),你可以用apt-mark auto把它改回去,这样下次清理时它就会被正常移除。

导出手动安装包列表用于环境迁移

这是apt-mark showmanual最经典的使用场景。当你要从一台Debian服务器迁移到另一台时,不需要把几百个依赖包都记下来,只需要导出手动安装列表,然后在新机器上批量安装即可。

导出命令:

apt-mark showmanual > manual_packages.txt

在新机器上批量安装:

xargs -a manual_packages.txt sudo apt install -y

或者更稳妥的写法,先更新再装:

sudo apt update
xargs -a manual_packages.txt sudo apt install -y

这样新机器就会自动拉取所有需要的依赖,你只需要维护一份简洁的手动包清单。这个方法比用dpkg --get-selections导出全部已安装包要干净得多,因为后者会包含大量你不需要的依赖。

配合apt-get autoremove清理无用依赖

了解了手动包和自动包的区别后,清理系统就变得非常有针对性。Debian提供了apt-get autoremove命令,它会自动移除所有标记为auto且没有被任何手动包依赖的包。但在执行之前,强烈建议先用apt-mark showmanual确认一下你的手动包列表,确保没有误装的东西。

安全清理流程:

# 第一步:查看当前手动安装的包,确认没有遗漏
apt-mark showmanual

# 第二步:模拟清理,看看会删掉什么(不真正执行)
sudo apt-get autoremove --dry-run

# 第三步:确认无误后执行清理
sudo apt-get autoremove -y

特别注意:如果你用apt-get install装了某个包,后来又用apt-get remove卸载了它,但没有加--purge或者没有执行autoremove,那这个包可能还留在系统里但标记变成了auto。这种情况下apt-mark showmanual不会显示它,但它确实占用着磁盘空间。所以清理要定期做,不能只看一次。

apt-mark showmanual和其他查看方式的对比

很多人会问,除了apt-mark showmanual,还有没有别的方法查看手动安装的包?有,但各有局限:

方法一:apt list --installed。这个命令列出所有已安装包,不区分手动和自动,信息太杂,不适合直接用。

方法二:apt-mark showmanual。精准、简洁、官方推荐,是最佳选择。

方法三:查看/var/lib/apt/extended_states文件。这个文件存储了包的状态信息,但格式不友好,不建议日常使用。

方法四:aptitude search '~i!~M'。aptitude是另一个包管理前端,这个命令可以查看已安装但非自动的包,效果类似但需要安装aptitude。

综合来看,apt-mark showmanual是最轻量、最直接、不需要额外安装任何工具的方案。

实际运维中的常见问题和解决方案

问题一:执行apt-mark showmanual后发现列表为空或者只有几个包,但我明明装了很多软件。

解答:这通常意味着你之前装的包已经被卸载了,或者你是用其他方式装的(比如从源码编译安装、用snap、flatpak等),这些方式安装的软件不会被apt标记。apt只管它自己管理的包。

问题二:想把某个自动包改成手动包,防止被autoremove清理掉。

解答:

sudo apt-mark manual 包名

比如你装了一个开发库,虽然当前没有手动包依赖它,但你知道以后会用到,就可以手动标记保护它。

问题三:系统升级后发现apt-mark showmanual的列表变了。

解答:这是正常的。大版本升级时,一些包可能被替换、合并或废弃,标记状态也会随之变化。建议在大版本升级前后都执行一次apt-mark showmanual做对比,确保关键包没有丢失。

问题四:如何查看某个包的详细安装信息,包括它是手动还是自动安装的。

解答:

apt-cache policy 包名

或者更详细的:

apt-cache showpkg 包名

这些命令可以看到包的版本、依赖关系、安装状态等完整信息。

进阶技巧:批量管理包标记

在管理大量服务器时,你可能需要批量操作包标记。比如把一组开发工具全部标记为manual,防止被误清理:

for pkg in git gcc make cmake python3-dev; do
    sudo apt-mark manual $pkg
done

或者从文件批量标记:

while read pkg; do
    sudo apt-mark manual "$pkg"
done < dev_tools.txt

反过来,如果要批量取消手动标记(把它们变回auto):

while read pkg; do
    sudo apt-mark auto "$pkg"
done < dev_tools.txt

这些脚本在自动化运维和配置管理中非常实用,可以写进Ansible playbook或者Shell脚本里反复使用。

总结与最佳实践

apt-mark showmanual是Debian/Ubuntu系统运维中一个小而精的命令,它解决的是"哪些包是我主动装的"这个核心问题。最佳实践建议:

第一,新服务器部署完成后立刻导出一份apt-mark showmanual的清单,作为基线备份。

第二,每次大版本升级前后对比手动包列表,确保环境一致性。

第三,定期执行apt-get autoremove配合apt-mark showmanual做系统瘦身,保持服务器精简。

第四,善用apt-mark manualapt-mark auto灵活调整包的标记状态,让包管理更可控。

第五,不要把apt-mark showmanual当成唯一的包管理依据,它只反映apt层面的安装状态,源码编译、容器化部署等方式安装的软件需要另外记录。

掌握这个命令,你对Debian系统的包管理理解会上一个台阶,日常运维效率也会明显提升。它不复杂,但用对了地方,价值很大。