FreeBSD pkg 命令概述
作者:重村法克
2025-02-09
介绍
由于 FreeBSD 中针对第三方工具引入的机制(Ports 和 Packages)的完善,二进制包的使用得到了发展。尤其是引入了 Flavors(版本)功能的好处尤为显著,尽管安装的内容是相同的,但由于依赖的包版本不同,组合的复杂性也随之增加。然而,只要为这些依赖包的所有版本提供相应的包,那么包管理就变得非常简单了。虽然我们希望所有的依赖包都能提供完整的包,但依然能够感受到二进制包带来的便利。
在这里,为了能够更好地利用二进制包,我总结了一些常用的命令。虽然详细的选项讲解会非常繁琐,但我只会列出常用的选项。此外,大多数命令在执行时都会询问是否继续。因此,几乎所有命令都可以使用 -y 选项来避免这一提示,我将在这里省略这一部分的详细描述。当你熟悉之后,可以自如使用。除此之外,我也没有列举太多实际操作的案例。如果你有任何疑问,欢迎告知,我会补充相关内容。
常用的 pkg 命令
在这里,我会在命令名称(或子命令名称)后标注 [R] 和 [L],它们的含义如下:
[R]:参考外部包/仓库中的信息。[L]:参考已安装的包或本地文件系统中的包。[RL]:根据环境的不同,既可以是[R]也可以是[L]。
pkg update [R]
这是用来收集包元数据的命令。首先需要收集元数据,其他命令的执行依赖于此。这与 yum check-update 很相似。
需要注意的是,这并不是一个每次都需要执行的命令,许多命令会在自动更新元数据后再执行,因此如果你不介意自动更新,便不需要手动执行该命令。以下子命令会基于最新的元数据执行:
pkg installpkg upgradepkg versionpkg searchpkg fetchpkg rquery
pkg install [R]
用于安装软件包。与后面提到的 pkg add 不同,pkg install 是通过关键词指定并从网络获取包来安装。
pkg add [L]
用于安装指定的包文件。与 pkg install 不同,pkg add 是明确指定包文件名并进行安装。
pkg delete [L]
删除指定的软件包。
pkg delete -ayf
使用 -a 选项删除所有包,-f 选项强制执行删除,并且 -y 选项使得操作不进行任何询问。直观上,指定 -ay 就足够了,但是在因依赖关系无法删除某些包时,必须指定 -f 选项。如果你打算删除所有包,毫不犹豫地全部指定就好。
pkg version [RL]
用于进行包的版本比较。由于其特殊性,使用时需要分解具体的用例来理解。
默认情况下,
pkg version会与/usr/ports/INDEX-OS major version这样的元数据文件进行比较。如果该文件不存在,会参考每个 Ports 的源目录(相当于指定
-P选项)。如果该目录也不存在,则会参考远程仓库(相当于指定
-R选项)。
前两种情况属于 [L] 范畴,而后者则属于 [R] 范畴。
pkg version -L =
通常使用 -L 选项进行已安装包的版本比较,使用 = 来显示没有匹配的包。通常情况下,只指定 = 就足够了,但也可以指定 >、<、?、! 等其他符号,所有这些符号都需要加引号。
以下是每个符号的含义,但在使用 -L 选项时,表示的是“非该符号”的情况。若需要查找该符号的含义,则需要使用 -l 选项。
>:当前安装的版本有较新的版本可用。=:当前安装的版本与发布的版本相同。<:当前安装的版本有较旧的版本可用,通常是元数据未更新或者进行新版本的测试安装时会出现。?:当前安装的包来源(origin)不存在,无法进行版本比较(可能已被删除或重命名)。!:当前安装的版本无法进行版本比较。
pkg version -t
用于比较任意指定的版本号(实际上是字符串)。这个功能更多是用于测试不同版本号之间的关系,而不是特定包的功能。它与其他子命令有所不同,主要用于测试版本号的替换(例如,在替换 alpha 版、beta 版时),帮助用户确定哪个版本更大(更新),哪个版本更小(更旧)。
关于版本比较的规则,你可以参阅 FreeBSD Porter's Handbook - 5.2.2. Versions, DISTVERSION or PORTVERSION。
pkg upgrade [R]
更新指定的包。如果没有特别指定,默认会检查所有包并尝试更新它们。
pkg info [L]
显示指定包的信息。如果没有指定包,则列出所有已安装包的概述。
pkg info -a
与其他选项一起使用时,表示列出所有包的信息。
pkg info -l
显示指定包的安装路径列表。
pkg info -D
显示指定包的注意事项,可能包含安装提示或其他相关信息。
pkg lock [L]
锁定指定包,防止其被更新。锁定的效果不仅限于防止包本身的更改,还包括以下功能:
阻止锁定包的重新安装、升级、降级和删除。
阻止依赖于锁定包的其他包的升级或降级,特别是当依赖关系指向另一个版本的锁定包时。
阻止锁定包依赖的其他包的删除、升级或降级。
即使间接共享依赖关系,也会被锁定。
pkg unlock [L]
解锁指定包。
pkg search [R]
使用正则表达式(大小写不敏感)搜索包名。通过 -e 选项可以进行严格的匹配,但这包括版本号,因此对于一般用户来说并不太友好。-g 选项支持类似于 shell glob(例如 ? 或 *)的模糊搜索,但由于版本号的包含,实际上搜索时需要加上 *。
pkg which [L]
显示指定的文件、目录等属于哪个包。使用 -o 选项可以显示该包的 origin。
不常用但值得了解的 pkg 命令
pkg audit [RL]
报告已安装包与漏洞信息的匹配结果。由于需要从外部获取漏洞信息,这个功能偏向 [R],但如果没有急于更新信息的需求,就无需通过 -F 选项主动获取漏洞信息。通常,系统会有一个脚本每天自动获取漏洞信息。
pkg check -s [L]
检查指定包是否未被篡改且保持一致性。通常与 -a 选项一起使用。
pkg check -d [L]
检查指定包的依赖是否完好,是否未损坏。通常与 -a 选项一起使用。
pkg autoremove [L]
删除孤立的包。所谓“孤立”的包是指因为依赖关系而安装,但由于某些包被删除或更新后不再被依赖,因此变得不再使用。
实际中,某些“孤立”的包可能仍在使用,但由于包的依赖信息无法反映这一点,因此在执行此操作时需要小心。例如,如果 bash 被作为某个包的依赖安装,但你仍在使用它,这种情况下就需要特别留意。可以通过显式安装 bash 或使用后续技巧避免此问题。
在 ports 系统中,通常是需要在构建过程中使用的包(如编译器等)会被标记为删除对象。
pkg updating [L]
显示需要注意的包更新步骤(手动更新指示)。具体来说,会读取 /usr/ports/UPDATING 文件,并根据安装的(或指定的)包信息匹配并显示相关内容。该文件的内容是为人类阅读设计的,构造上有些启发式,但其严格性可能并不高。此外,需要确保该文件存在,系统不会自动下载该文件。
pkg set [L]
修改指定包的元数据(数据库)。通常是在根据 pkg updating 信息操作时才会用到这个命令,一般不需要主动使用。
pkg set -A
通过为 -A 选项指定以下值,来修改指定包的元数据。此更改会影响 pkg autoremove 的行为结果。
0:使指定的包不成为pkg autoremove的删除对象。1:使指定的包成为pkg autoremove的删除对象。
对这个选项感兴趣的人,可能也会关心 pkg autoremove 的工作原理。实际上,仅设置这个标志并不足以使包成为 pkg autoremove 的目标;还需要判断该包没有被其他包依赖等条件。
另外,通过 pkg install 或 pkg add 明确指定安装的包,在安装时会自动设置为此标志无效。这个标志只对因依赖关系被自动安装的包有效。
pkg set -o
使用 -o 旧 origin:新 origin 的形式,将所有依赖旧 origin 的包的元数据中的 origin 信息修改为新值。
pkg set -n
使用 -n 旧包名:新包名 的形式修改包名。不过,考虑到包名中通常不包含版本号,这个操作本身存在一些微妙的问题。
太小众了其实可以不用知道的 pkg 命令
pkg alias [L]
显示定义在 /usr/local/etc/pkg.conf 中的别名信息。
pkg query [L]
以指定的格式显示软件包的元信息。如果未指定包名,则会针对所有已安装的包进行查询。 可用于格式字符串中的占位符如下所示:
%n:包名%v:包的版本%o:包的 origin%p:包的 prefix%m:包的维护者(电子邮件地址)%c:包的注释%e:包的描述%w:包的网址%l:包的许可证逻辑(无 / 单一 /and/or)%sb或%sh:包的大小(字节单位或更适合人类阅读的单位)%a:包的自动安装标志%Q:包支持的架构候选项%q:包的架构(操作系统、版本、CPU 架构)%k:包的锁定标志%M:包的信息消息%t:包的安装时间戳%R:包的安装来源仓库%X:包的校验和%?C:表示某种条件C是否成立的布尔标志(d/r/C/F/O/D/L/U/G/B/b/A,各自说明略)%#C:满足某种条件C的项目数(与上同)%dC:该包依赖的其他包列表,通过C(具体为n/o/v)来选择输出 Name/Origin/Version%rC:依赖于该包的其他包列表,通过C(具体为n/o/v)来选择输出 Name/Origin/Version%C:包所属的分类列表%FC:包包含的文件列表,通过C(p/s)来选择 Path 或校验和 Sum%D:包包含的目录列表%OC:包的选项列表,通过C(k/v/d/D)来选择 key、value、默认值、描述%L:包的许可证列表%U:包使用的用户列表%G:包使用的用户组列表%B:包在程序中使用的共享库列表%b:包所提供的共享库列表%AC:包的注解标签列表,通过C(t/v)选择 tag 或 value
常见的用法之一是 %n-%v,用于输出包名和版本的组合形式。
pkg query -e
用于根据指定的查询条件筛选符合条件的软件包。以下是可用于右侧(不能用于左侧)条件表达式的字段:
%n:包名(字符串型)%o:包的 origin(字符串型)%p:包的 prefix(字符串型)%m:包的维护者(邮箱,字符串型)%c:包的注释(字符串型)%e:包的描述(字符串型)%w:包的网址(字符串型)%s:包的大小(字节单位,数值型)%a:包的自动安装标志(数值型)%q:包的架构(操作系统、版本、CPU 架构,字符串型)%k:包的锁定标志(数值型)%M:包的信息消息(字符串型)%t:包的安装时间戳(数值型)%i:包的附加信息(字符串型)%#C:表示某类项目的数量(C可为d/r/C/F/O/D/L/U/G/B/b/A,说明略)
可使用的运算符如下:
||:逻辑“或”,用于连接两个判断条件&&:逻辑“与”,用于连接两个判断条件~:用于匹配 glob 模式,例如%var ~ 模式,判断是否匹配!~:用于判断是否不匹配 glob 模式>/>=:用于数值比较,大于或大于等于</<=:用于数值比较,小于或小于等于=/==:判断是否等于(数字或字符串)!=:判断是否不等于(数字或字符串)=~:判断是否大小写不敏感地等于(数字或字符串)!=~:判断是否大小写不敏感地不等于(数字或字符串)
pkg rquery [R]
作用类似于 pkg query,但用于远程元数据。不再赘述,请参见 pkg query 的说明。
pkg annotate [L]
用于为软件包添加、修改或删除“注释信息标签”的命令。
这些注释信息可通过 pkg info -A 查看。至于注释标签的具体含义与使用方式,此处不做特别说明。
pkg shell [L]
用于直接访问管理软件包元数据的数据库(即 SQLite3)的命令。
基本上只能用来执行类似 pkg shell VACUUM 这样的操作。
如果你只是想利用查询功能,用 pkg query 就已经绰绰有余了,这个命令实用性很低。
便利的别名命令
与自动安装标志相关
以下命令是别名,用于筛选出“自动安装标志为 0”的软件包,即那些是用户显式安装的包:
pkg prime-list[L]pkg prime-origins[L]pkg noauto[L]
pkg leaf [L]
显示所有“叶子”软件包,即在依赖树最下层的包。
若某个软件包出现在这里但不出现在 pkg noauto 中,则它是 pkg autoremove 的候选对象。
pkg list [L]
显示指定软件包所安装的文件路径列表。
语法糖
以下是等价的命令别名,可以任选其一来执行操作。
甚至你可以用像 pkg vanish(消失)这种中二感满满的词自定义别名,只要你愿意。
系统默认提供了一些比较中性的别名。
pkg remove等价于pkg delete
不需要在意的 pkg 命令们
这些命令大多是供内部使用的,或是给其他工具调用使用(比如把别的包管理系统的软件包信息注册到 FreeBSD 的 pkg 系统中)。 一般用户不需要关心:
pkg stats:显示统计信息pkg clean:清理包缓存pkg config:查看/usr/local/etc/pkg.conf中的设置(大小写不敏感)pkg create:创建软件包。虽然在 Ports 构建过程中常用,但很少单独使用pkg fetch:下载包。pkg install实际上等价于pkg fetch加上pkg addpkg register:将包注册进本地数据库。纯粹是内部用途pkg repo:生成包仓库目录,相关内容建议参考pkg-repository(5)手册pkg shlib:显示软件包所提供的共享库以及依赖这些库的其他包,主要用于安全审计pkg ssh:完全用于内部,不适合人类用户使用,省略pkg triggers:执行延迟触发器。这是什么时候谁延迟的?总之也是内部使用,省略
查询(pkg-query)
想查出依赖于某个包,且是“显式安装”的所有软件包
以 Python 3.11 为例,说明如何列出“依赖 Python 3.11 且是用户明确指定安装”的所有软件包。
首先可以使用 pkg info -r python311(按包名指定)列出所有依赖 Python 3.11 的软件包。
也可以使用 pkg query '%ro' python311 以“原始名称”(origin)来列出。
此外,也可以直接使用如 lang/python311 这样的 origin 作为指定方式,而非包名。
接着,检查这些软件包的“自动安装标志”,只列出自动安装标志为 0 的,即明确安装的那些。 示例如下:
pkg query -e "%a = 0" "%n" $(pkg info -r python311)
或者
pkg query -e "%a = 0" "%n" $(pkg query '%ro' python311)由于没有很干净的一条命令就能完成所有功能的写法,因此也可以借助 pkg shell 来做(不推荐,供参考)。
注意:此方法依赖底层数据库结构,未来可能失效。
pkg shell -cmd "SELECT p.name FROM deps AS d INNER JOIN packages AS p ON package_id = p.id WHERE d.origin = 'lang/python311' AND p.automatic = 0" < /dev/null常见问题及解答
Q. 什么是 origin?
A.Origin 是什么以后再说吧。有空我再写。
Q.pkg 命令本身是一个软件包吗?
A. 是的,pkg 命令本身就是一个包。
Q. 那 /usr/sbin/pkg 是什么?
/usr/sbin/pkg 是什么?A. 那是一个“引导器”,只负责安装真正的 pkg 包。
实际会执行的是 pkg 包里的 /usr/local/bin/pkg-static。
Q. 那它不属于基本系统吗?
A.FreeBSD 曾经因为旧的软件包系统吃了太多苦,所以才采用了现在这种结构。 以前 pkg 命令不升级,整个系统就什么都干不了(即使新版本系统已经发布了,还会强制用老功能)。
Q.pkg 命令和 pkg-static 命令有什么区别?
A. 功能完全一样。pkg-static 主要在某些“极端情况”(如你要删掉 pkg 本身)时才需要。
一般正常使用用 pkg 就够了;pkg-static 只是为了某些内部处理时更安全。
Q. 如何删除通过 pkg update 获取的仓库信息?
pkg update 获取的仓库信息?A. 我也很感兴趣,目前还在调查中。
Q. 用 pkg query 过滤总是不太顺利啊。比如说,想列出“最后安装的包”怎么办?
pkg query 过滤总是不太顺利啊。比如说,想列出“最后安装的包”怎么办?A. 这种时候可以用 pkg shell 来努力一下。虽说“让我们来写 SQL 吧!”这听起来有点夸张,但你说得没错,pkg query 并不支持排序或聚合。
另一种思路是,把 pkg query 的输出通过管道传给其它工具,比如 sort、awk、head、tail 等组合使用。
Q. 你真的全都记得住?
A. 常用的当然记得住。原以为我也就记了三五个而已,没想到写着写着就十几个浮现脑海。说明这些的确值得记。 虽然有些细节的语义可能模糊了,但那种情况就查下手册吧。 总之,平时不常用的,忘了也无妨。
顺便说一下,pkg query 和 pkg shell 以前我其实用得不多,这次因为研究查数据才顺手补上的。虽然 pkg shell 基本就是只查结果而已。
Q.pkg update / upgrade / updating 总是傻傻分不清楚
A. 很遗憾,这是必须记下来的。
其他包管理器有时 update 和 upgrade 是同一个东西,但在 FreeBSD 上……很遗憾(信息在此中断了)。
Q.WITH_PKGNG 和 pkg2ng 是什么?
A. 这是非常古早(比 10.0-RELEASE 还早)的事情,完全可以无视。 它们只具备历史意义,现在的设置和运维里已经毫无价值。
小吐槽
刚列完这些“大家应该都知道吧”的命令,立马陷入绝望:平时常用到底是指哪些……? 但如果不写这些,又感觉内容不完整,简直是地狱。 结果还在翻 man 手册时发现了个 bug(pkg-query(8): duplicate %#b),orz。
参考文献
最后更新于
这有帮助吗?