apk 命令详解与参数实测(Alpine Linux)
在 Alpine Linux 3.24.2(apk-tools 3.0.8,v3 命令族)实测逐参数讲解 apk:add/del/update/upgrade/search/info/fetch/cache/policy/list/query/fix/audit/index 全命令常用参数与真实回显,覆盖 --virtual 包束、--allow-untrusted 信任控制、--root 构建 chroot 根、本地仓库搭建、@tag 标签仓库、换源排障,并整理 apk v2→v3 行为差异对照。
apk 命令详解与参数实测(Alpine Linux)
目标:全面掌握 Alpine Linux 包管理器 apk 的每一个常用操作——
add安装、--virtual包束、del/--rdepends删除、update与/etc/apk/repositories软件源管理、upgrade/version升级与版本比较、search/info/list/query/policy查询、fetch仅下载、cache缓存管理、fix/audit修复巡检、index/mkndx搭建本地仓库,以及--allow-untrusted/--keys-dir/--root/--initdb/--repositories-file/-X等关键全局参数,全部命令与回显已在 Alpine Linux 3.24.2(apk-tools 3.0.8)实测通过。
一、环境信息
本文所有命令均在以下环境实测,回显逐字照抄:
- 操作系统:Alpine Linux 3.24.2(
/etc/alpine-release实测;/etc/os-release实测PRETTY_NAME="Alpine Linux v3.24") - 内核架构:x86_64(
uname -m实测) - 包管理器:apk-tools 3.0.8-r0(
apk --version实测),配套库 libapk 3.0.8-r0 - C 标准库:musl 1.2.6-r2;基础工具箱:busybox 1.37.0-r31
- 初始状态:全新最小系统,已安装 20 个包,
/etc/apk/world共 7 项顶层约束 - 软件源:
/etc/apk/repositories共 2 条(dl-cdn.alpinelinux.org 的 v3.24 main 与 community) - 执行身份:root(uid=0)
- 演示包(体积小、便于反复装卸):tree 2.3.2-r0、htop 3.5.3-r0、lsof 4.99.6-r0、bc 1.08.2-r1、sl 5.02-r1、busybox-openrc 1.37.0-r31
💡 说明:Alpine 的「小」来自两个底层基因——musl 与 busybox,这也直接决定了 apk 的依赖写法。与 glibc 系发行版对比——
维度 Alpine(本文) Debian/Ubuntu RHEL/Fedora Arch C 库 musl(轻量、严格 POSIX) glibc glibc glibc 基础工具箱 busybox(一个二进制实现数百命令) GNU coreutils 等各自成包 GNU coreutils GNU coreutils 包管理器 apk(本文) apt/dpkg dnf/rpm pacman 依赖表示 支持 so:libc.musl-x86_64.so.1、cmd:bash这类「能力依赖」按包名/虚拟包名 按包名/能力 按包名 本文实测中
apk info -R htop输出的so:libc.musl-x86_64.so.1就是 musl 依赖的写法:apk 把「共享库」「命令」也抽象成可依赖的原子(atom),而非只认包名。
💡 技术拓展:网上大量 apk 教程基于 apk-tools 2.x,而 Alpine 3.24 已随 apk-tools 3.x(v3 命令族),两代行为差异不小。本文实测(apk-tools 3.0.8)与 2.x 教程的关键差异先列出来,后文各节再逐点验证:
差异点 apk-tools 2.x(旧教程) apk-tools 3.0.8(本文实测) --no-cache独立参数 变为布尔取反语法(等价 --cache=false),仍可用apk info -o(查 origin)存在 已移除,报 unrecognized option 'o'(3.6 节实测)apk fetch -R-R/--recursive属 fetch 自有参数递归由通用查询参数 --recursive提供,-R短参仍可用(3.7 节实测)apk cache v部分版本可用 子命令不存在,静默退出码 99(3.8 节实测) apk del保留依赖时输出 warning 格式不同 输出 World updated, but the following packages are not removed due to:(3.2 节实测)查询体系 info/search各自为政新增统一查询入口 query,支持--format yaml/json(3.11 节实测)在自己环境确认代次:
apk --version输出apk-tools 3.x即本文体系,2.x则需按旧教程对照。
二、命令概览
2.1 设计模型与 --help 全量回显
apk 的命令行模型是「全局参数 + 子命令 + 子命令参数」:apk [<全局选项>...] COMMAND [<选项>...] [<参数>...]。它没有 pacman 那种「一个大写字母定操作」的设计,而是拆成二十多个小写子命令。最核心的概念是 WORLD(世界约束):/etc/apk/world 记录「用户显式要求系统里有什么」,apk add/apk del 本质上是在增删这份约束清单,然后由求解器把系统调整到与约束一致的状态——多余的依赖会被自动清掉,无需 autoremove。以下为 apk --help 的完整实测输出:
$ apk --help
apk-tools 3.0.8-r0, compiled for x86_64.
Usage: apk [<GLOBAL OPTIONS>...] COMMAND [<OPTIONS>...] [<ARGUMENTS>...]
Package installation and removal:
add Add or modify constraints in WORLD and commit changes
del Remove constraints from WORLD and commit changes
System maintenance:
fix Fix, reinstall or upgrade packages without modifying WORLD
update Update repository indexes
upgrade Install upgrades available from repositories
cache Manage the local package cache
Querying package information:
query Query information about packages by various criteria
list List packages matching a pattern or other criteria
dot Render dependencies as graphviz graphs
policy Show repository policy for packages
search Search for packages by name or description
info Give detailed information about packages or repositories
Repository and package maintenance:
mkndx Create repository index (v3) file from packages
mkpkg Create package (v3)
index Create repository index (v2) file from packages
fetch Download packages from repositories to a local directory
manifest Show checksums of package contents
extract Extract package file contents
verify Verify package integrity and signature
adbsign Sign, resign or recompress v3 packages and indexes
Miscellaneous:
audit Audit system for changes
stats Show statistics about repositories and installations
version Compare package versions or perform tests on version strings
adbdump Dump v3 files in textual representation
adbgen Generate v3 files from text representation
convdb Convert v2 installed database to v3 format
convndx Convert v2 indexes to v3 format
This apk has coffee making abilities.
For more information: man 8 apk
按帮助里的分组,把日常会用到的命令归一下类:
| 分组 | 命令 | 用途 |
|---|---|---|
| 安装与卸载 | add / del | 修改 WORLD 并提交变更(装/删) |
| 系统维护 | fix / update / upgrade / cache | 修复、刷新索引、升级、管理缓存 |
| 查询 | query / list / dot / policy / search / info | 各种维度的包信息查询 |
| 仓库与包维护 | mkndx / mkpkg / index / fetch / manifest / extract / verify / adbsign | 建索引、打包、下载、校验 |
| 杂项 | audit / stats / version / adbdump / adbgen / convdb / convndx | 巡检、统计、版本比较、格式转换 |
💡 技术拓展:四大主流发行版包管理器的设计差异(本文所用为 apk)——
维度 apk(Alpine) apt(Debian 系) dnf(RHEL 系) pacman(Arch) 数据库 /lib/apk/db/installed(文本 tar)/var/lib/dpkg + apt Lists rpmdb + metadata /var/lib/pacman(tar) 顶层意图 WORLD 文件( /etc/apk/world)手动安装标记(apt-mark) yumdb/reason 标记 安装原因字段 依赖清理 del 即时自动清依赖 autoremove autoremove -Rs 显式递归 索引刷新 按缓存时长自动刷新, update强制update makecache/check-update -Sy 强制 包格式 .apk(未压缩 tar 流) .deb .rpm .pkg.tar.zst apk 的「WORLD 即真相」是它最独特的设计:系统永远被求解成与 world 约束一致的最小状态,因此没有 autoremove 这个概念。本文因目标场景是精简系统与快速装卸演示包,直接使用默认行为。
2.2 版本信息
apk --version
apk --print-arch
apk -V
实测回显:
$ apk --version
apk-tools 3.0.8-r0, compiled for x86_64.
$ apk --print-arch
x86_64
$ apk -V
apk-tools 3.0.8-r0, compiled for x86_64.
💡 说明:
--version与短参-V等价;--print-arch打印 apk 认定的默认架构(决定它去仓库的x86_64/子目录取包)。apk 版本查询不区分「程序版本」与「包版本」——包版本要查apk list --installed apk-tools(3.10 节)。
2.3 全局参数与子命令参数
每个子命令的 --help 都由三段组成:Global options(全局参数,所有子命令相同)、Commit options(提交类参数,所有会改系统的子命令相同)、该子命令的专属参数。以 apk add --help 为例完整实测(其余子命令不再重复贴全局段,只贴专属段):
$ apk add --help
apk-tools 3.0.8-r0, compiled for x86_64.
Usage: apk add [<OPTIONS>...] [CONSTRAINTS|_file_]...
Description:
apk add adds or updates given constraints to WORLD (see apk-world(5)) and
commit changes to disk. This usually involves installing new packages, but
may also cause other changes to the installed packages.
Global options:
--allow-untrusted Install packages with untrusted signature or no
signature
--arch ARCH Temporarily override architectures
--cache[=BOOL] When disabled, prevents using any local cache paths
--cache-dir CACHEDIR Temporarily override the cache directory
--cache-max-age AGE Maximum AGE (in minutes) for index in cache before
it's refreshed
--cache-packages[=BOOL]
Store a copy of packages at installation time to
cache
--cache-predownload[=BOOL]
Download needed packages to cache before starting to
commit a transaction
--check-certificate[=BOOL]
When disabled, omits the validation of the HTTPS
server certificate
--force, -f Enable selected --force-* options (deprecated)
--force-binary-stdout
Continue even if binary data will be printed to the
terminal
--force-broken-world DANGEROUS: Delete world constraints until a solution
without conflicts is found
--force-missing-repositories
Continue even if some of the repository indexes are
not available
--force-no-chroot Disable chroot for scripts
--force-non-repository
Continue even if packages may be lost on reboot
--force-old-apk Continue even if packages use unsupported features
--force-overwrite Overwrite files in other packages
--force-refresh Do not use cached files (local or from proxy)
--help, -h Print the list of all commands with descriptions
--interactive[=AUTO] Determine if questions can be asked before
performing certain operations
--keys-dir KEYSDIR Override the default system trusted keys directories
--legacy-info[=BOOL] Print output from "info" applet in legacy format or
new "query" format
--logfile[=BOOL] If turned off, disables the writing of the log file
--network[=BOOL] If turned off, does not use the network
--preserve-env[=BOOL]
Allow passing the user environment down to scripts
(excluding variables starting APK_ which are
reserved)
--pretty-print[=AUTO]
Determine if output should be stylized to be human
readable
--preupgrade-depends DEPS
Add or modify preupgrade dependencies
--print-arch Print default arch and exit
--progress[=AUTO] Enable or disable progress bar
--progress-fd FD Write progress to the specified file descriptor
--purge[=BOOL] Purge modified configuration and cached packages
--quiet, -q Print less information
--repositories-file REPOFILE
Override system repositories, see
apk-repositories(5)
--repository, -X REPO
Specify additional package repository
--repository-config REPOCONFIG
Specify additional package repository configuration
--root, -p ROOT Manage file system at ROOT
--root-tmpfs[=AUTO] Specify if the ROOT is a temporary filesystem
--sync[=AUTO] Determine if filesystem caches should be committed
to disk
--timeout TIME Timeout network connections if no progress is made
in TIME seconds
--update-cache, -U Alias for '--cache-max-age 0'
--uvol-manager UVOL Specify the OpenWRT UVOL volume manager executable
location
--verbose, -v Print more information (can be specified twice)
--version, -V Print program version and exit
--wait TIME Wait for TIME seconds to get an exclusive repository
lock before failing
Commit options:
--clean-protected[=BOOL]
If disabled, prevents creation of .apk-new files in
configuration directories
--commit-hooks[=BOOL]
If disabled, skips the pre/post hook scripts (but
not other scripts)
--initramfs-diskless-boot
Used by initramfs when it's recreating root tmpfs
--overlay-from-stdin Read list of overlay files from stdin
--scripts[=BOOL] If disabled, prevents execution of all scripts
--simulate[=BOOL], -s
Simulate the requested operation without making any
changes
Add options:
--initdb Initialize a new package database
--latest, -l Always choose the latest package by version
--no-chown Deprecated alias for --usermode
--upgrade, -u Upgrade PACKAGES and their dependencies
--usermode Create usermode database with --initdb
--virtual, -t NAME Create virtual package NAME with given dependencies
For more information: man 8 apk-add
全局参数太多,先按使用频率抓大放小,本文会实测的重点参数如下表(未列出的冷门参数见上方完整帮助):
| 参数 | 作用 | 实测位置 |
|---|---|---|
--allow-untrusted | 放行未签名/签名不受信的包与索引 | 3.13/3.14 节 |
--keys-dir KEYSDIR | 覆盖信任密钥目录 | 3.14 节 |
--repository, -X REPO | 临时附加一个仓库 | 3.3 节 |
--repositories-file FILE | 用指定文件整体覆盖软件源 | 3.3 节 |
--root, -p ROOT | 把 ROOT 当系统根操作 | 3.15 节 |
--update-cache, -U | 强制刷新索引缓存(等价 --cache-max-age 0) | 3.1 节 |
--network[=BOOL] | 禁网取反写法 --no-network | 3.8 节 |
--simulate, -s | 模拟不落盘(提交类通用) | 3.1 节 |
--quiet, -q / --verbose, -v | 减少/增加输出 | 3.5 节 |
--cache-dir / --purge | 缓存目录覆盖 / 清理配置残留 | 3.8 节、五节 FAQ |
💡 说明:布尔型参数在 apk-tools 3.x 里统一支持
[=BOOL]后缀与--no-取反前缀两种写法,例如--no-cache等价--cache=false、--no-network等价--network=false。这就是为什么旧教程的apk add --no-cache在 3.x 依然能跑通——它不再是一个独立参数,而是取反语法(3.1 节实测)。
2.4 测试数据准备
apk 的一切状态都在 /etc/apk/ 与 /lib/apk/db/ 两个目录里,先看初始基线:
ls /etc/apk/
cat /etc/apk/repositories
cat /etc/apk/world
apk update
apk stats
实测回显:
$ ls /etc/apk/
arch
keys
protected_paths.d
repositories
world
$ cat /etc/apk/repositories
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
https://dl-cdn.alpinelinux.org/alpine/v3.24/community
$ cat /etc/apk/world
alpine-baselayout
alpine-keys
alpine-release
apk-tools
bash
busybox
musl-utils
$ apk update
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/main]
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/community]
OK: 28668 distinct packages available
$ apk stats
installed:
packages: 20
dirs: 113
files: 199
bytes: 10530402
triggers: 1
available:
names: 70501
packages: 28668
atoms:
num: 60812
配置解读:/etc/apk/repositories 每行一个仓库地址;/etc/apk/world 每行一个顶层包约束(还可带版本限制,如 zlib<1.4);/etc/apk/keys/ 存放仓库签名公钥;arch 记录目标架构。apk update 输出里 v3.24.2-153-gf688430cdb9 是索引快照的 git 提交号(随上游更新而变,读者复测时数字不同属正常),OK: 28668 distinct packages available 是两个仓库去重后的可用包总数;apk stats 中 installed: 20 与前述初始基线一致,atoms: 60812 是索引中「包名/so:/cmd:」原子的总数。
三、参数逐项实测
3.1 apk add:安装包并修改 WORLD
add 是使用频率最高的子命令:把包名写入 WORLD 并立即求解安装,依赖自动带入。基础安装与验证:
apk add tree
apk info -e tree
apk add tree
实测回显:
$ apk add tree
(1/1) Installing tree (2.3.2-r0)
Executing busybox-1.37.0-r31.trigger
OK: 10.1 MiB in 21 packages
$ apk info -e tree
tree
$ apk add tree(再次安装已安装包)
OK: 10.1 MiB in 21 packages
已安装的包重复 add 是无操作(输出 OK 但没有任何 Installing 行)。
--no-cache:安装前不用本地索引缓存(等价 --cache=false,先强制刷新索引):
apk add --no-cache htop
实测回显:
$ apk add --no-cache htop
(1/2) Installing lsof (4.99.6-r0)
(2/2) Installing htop (3.5.3-r0)
Executing busybox-1.37.0-r31.trigger
OK: 10.7 MiB in 23 packages
注意 htop 把 lsof 一并带入(htop 3.5.3 依赖 lsof 做进程文件查询),这是 1.2 节说的 so:/依赖原子解析在起作用。
--simulate(-s):模拟安装不落盘:
apk add --simulate sl
cat /etc/apk/world
实测回显:
$ apk add --simulate sl(模拟安装不落盘)
(1/1) Installing sl (5.02-r1)
OK: 10.7 MiB in 24 packages
$ cat /etc/apk/world(模拟安装后 world 未变化)
alpine-baselayout
alpine-keys
alpine-release
apk-tools
bash
busybox
htop
musl-utils
tree
模拟模式会完整跑一遍求解器并打印将发生的变更,但 world 文件与磁盘都保持原样。上生产变更前先 -s 看一眼是 apk 最值得养成的习惯。
--progress:强制显示进度条(默认在非交互窄输出下不画):
$ apk add --progress bc
(1/1) Installing bc (1.08.2-r1)
<ESC>7 0% <ESC>8<ESC>[0K<ESC>7 46% #################### <ESC>8<ESC>[0K<ESC>7100% ############################################<ESC>8<ESC>[0KExecuting busybox-1.37.0-r31.trigger
OK: 10.8 MiB in 24 packages
(<ESC> 为转义控制字符的书面标记:进度条刷新使用 ESC 7/ESC 8 保存恢复光标、ESC[0K 清行,逐字原样包含这些控制字节无法在文档中呈现,此处按序列写出。)
不存在的包——错误回显与退出码:
$ apk add nosuch-package-demo(不存在的包)
ERROR: unable to select packages:
nosuch-package-demo (no such package):
required by: world[nosuch-package-demo]
退出码=1
--virtual(-t):把一批包捆绑成一个可整体卸除的虚拟包:
apk add --virtual buildenv make
apk info -e make
grep buildenv /etc/apk/world
apk del buildenv
apk info -e make
实测回显:
$ apk add --virtual buildenv make
(1/2) Installing make (4.4.1-r4)
(2/2) Installing buildenv (20261016.162300)
Executing busybox-1.37.0-r31.trigger
OK: 11.0 MiB in 26 packages
$ apk info -e make
make
$ grep buildenv /etc/apk/world
buildenv=20261016.162300
$ apk del buildenv(删除虚拟包即连带清理 make)
(1/2) Purging buildenv (20261016.162300)
(2/2) Purging make (4.4.1-r4)
Executing busybox-1.37.0-r31.trigger
OK: 10.8 MiB in 24 packages
$ apk info -e make
退出码=1
💡 技术拓展:「把一批包捆成一个名字、用完一删全走」的包束机制各家实现对比——
方案 代表 原理 适用 虚拟包 apk --virtual(本文)world 里写一条 名字=时间戳约束,成员包挂其下临时构建环境,del 虚拟名即全清 组包(group/meta) dnf @group、apttasksel仓库侧定义元包,装组名即装成员 安装成套功能(如开发工具组) 包组 pacman 基础组/ -S 组名仓库元包 + 安装原因追踪 成套安装,卸载需配合 -Rs 事务回滚 dnf history / nix generations 记录事务,整段撤销 需要回滚能力的场景 本文实测采用 apk 原生
--virtual:无需仓库侧定义、时间戳版本号天然防重名,是 Alpine 上跑 CI/编译任务的标准姿势。
-u(--upgrade):add 时对已装包按升级语义重新解析;-U(--update-cache):解析前强制刷新索引缓存:
$ apk add -u --simulate bc(-u/--upgrade:无新版本时无操作)
OK: 10.2 MiB in 21 packages
$ apk add -U --simulate htop(-U/--update-cache:先强制刷新索引再解析)
(1/2) Installing lsof (4.99.6-r0)
(2/2) Installing htop (3.5.3-r0)
OK: 10.7 MiB in 23 packages
-u 与裸 add 的区别在「已装包存在新版本」时才体现:裸 add 视「已满足」为完成,-u 会把指定包及其依赖升到最新。-U 是全局参数(--cache-max-age 0 的别名),适合脚本里确保拿到最新索引。
本地 .apk 文件直接安装(路径必须带 /,纯文件名会被当成包名):
$ apk add /tmp/pkgdl/tree-2.3.2-r0.apk(本地 .apk 文件直接安装:官方密钥可验签)
(1/1) Installing tree (2.3.2-r0)
Executing busybox-1.37.0-r31.trigger
OK: 10.1 MiB in 21 packages
$ apk info -e tree
tree
安装动作的落点在 /lib/apk/db/(安装数据库):
$ ls /lib/apk/db/(安装数据库所在目录)
installed
lock
scripts.tar.gz
triggers
3.2 apk del:删除包并收缩 WORLD
del 从 WORLD 移除约束并提交变更:约束没了、且不再被其他包需要的依赖会被立即自动清除。基础行为与「未安装包」的处理:
$ apk del sl(删除未安装的包)
OK: 10.8 MiB in 24 packages
$ apk del tree bc htop(清理实测演示包)
(1/4) Purging bc (1.08.2-r1)
(2/4) Purging htop (3.5.3-r0)
(3/4) Purging lsof (4.99.6-r0)
(4/4) Purging tree (2.3.2-r0)
Executing busybox-1.37.0-r31.trigger
OK: 10.0 MiB in 20 packages
$ apk info -e tree
退出码=1
$ cat /etc/apk/world(删除后 world 同步收缩)
alpine-baselayout
alpine-keys
alpine-release
apk-tools
bash
busybox
musl-utils
注意 lsof 并不在 world 里(它是 htop 的依赖),但因为唯一需求方 htop 被删,也一并 Purge 了——这就是 WORLD 模型「删约束带清依赖」的直接体现,不需要 apt autoremove。
del 一个仍被别的顶层包依赖的包:apk 只摘除约束、不动包本身,并明确提示原因。构造 htop 与 lsof 同时在 world 的场景对比:
$ apk info -r lsof(lsof 的反向依赖)
lsof-4.99.6-r0 is required by:
htop-3.5.3-r0
$ apk del lsof(不带 -r:仅移除 WORLD 约束,依赖仍被 htop 需要而保留)
World updated, but the following packages are not removed due to:
lsof: htop
OK: 10.6 MiB in 22 packages
$ apk info -e lsof(lsof 实际还在)
lsof
$ apk del --rdepends lsof(-r:连同顶层反向依赖 htop 一起删除)
(1/2) Purging htop (3.5.3-r0)
(2/2) Purging lsof (4.99.6-r0)
Executing busybox-1.37.0-r31.trigger
OK: 10.0 MiB in 20 packages
$ apk info -e htop(htop 被连带删除)
退出码=1
--rdepends(-r)是 del 的唯一专属参数:递归把「顶层(在 world 里的)反向依赖」也删掉。上例中 world 同时有 htop 和 lsof,del -r lsof 就把依赖 lsof 的 htop 一起带走。而裸 del lsof 的提示 lsof: htop 含义是「lsof 还没删,因为 htop 还需要它」。
3.3 apk update 与 /etc/apk/repositories:软件源管理
update 强制刷新所有仓库索引。apk-tools 3 日常装包不强制先 update——索引缓存超时后任何需要索引的子命令都会自动刷新;update 的价值是立即拉新与排障。/etc/apk/repositories 的格式规则:每行一个仓库地址;# 开头为注释(可用于临时禁用仓库);支持 @标签 地址 语法定义标签仓库。先看注释禁用与恢复(改配置前后都 cat 留痕):
$ cp /etc/apk/repositories /tmp/repositories.bak2 && cat /etc/apk/repositories(软件源编辑流程重跑)
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
https://dl-cdn.alpinelinux.org/alpine/v3.24/community
$ sed -i "s|^https://dl-cdn.alpinelinux.org/alpine/v3.24/community|# &|" /etc/apk/repositories(注释禁用 community)
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
# https://dl-cdn.alpinelinux.org/alpine/v3.24/community
$ apk update(仅 main 生效)
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/main]
OK: 5961 distinct packages available
可用包从 28668 掉到 5961,community 被禁用生效。恢复后整体切换到清华大学 TUNA 镜像(国内服务器标准操作):
$ sed -i "s|dl-cdn.alpinelinux.org|mirrors.tuna.tsinghua.edu.cn|g" /etc/apk/repositories(切换 TUNA 镜像)
https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.24/main
https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.24/community
$ apk update(TUNA 镜像生效)
v3.24.2-153-gf688430cdb9 [https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.24/main]
v3.24.2-153-gf688430cdb9 [https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.24/community]
OK: 28668 distinct packages available
$ sed -i "s|mirrors.tuna.tsinghua.edu.cn|dl-cdn.alpinelinux.org|g" /etc/apk/repositories(恢复官方源)
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
https://dl-cdn.alpinelinux.org/alpine/v3.24/community
$ apk update(恢复后校验)
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/main]
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/community]
OK: 28668 distinct packages available
@tag 标签仓库:在 repositories 文件里用 @名字 给某行仓库打标签,之后只有显式以 包名@标签 引用时才会用该仓库,适合「默认稳定版、按需取新版」:
$ printf "https://dl-cdn.alpinelinux.org/alpine/v3.24/main\n@edge https://dl-cdn.alpinelinux.org/alpine/edge/main\n" > /tmp/repotag(@tag 标签仓库语法)
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
@edge https://dl-cdn.alpinelinux.org/alpine/edge/main
$ apk update --repositories-file /tmp/repotag(update 会同时刷新标签仓库索引)
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/main]
v20260805-4263-g60322b8815d [https://dl-cdn.alpinelinux.org/alpine/edge/main]
OK: 11635 distinct packages available
$ apk add --simulate --repositories-file /tmp/repotag "busybox@edge"(尝试从 edge 标签仓库安装)
(1/5) Purging busybox-binsh (1.37.0-r31)
(2/5) Upgrading busybox@edge (1.37.0-r31 -> 1.38.0-r7)
(3/5) Installing dash (0.5.13.1-r2)
(4/5) Installing dash-binsh (0.5.13.1-r2)
(5/5) Upgrading ssl_client@edge (1.37.0-r31 -> 1.38.0-r7)
OK: 10.2 MiB in 22 packages
busybox@edge 把 busybox(及其依赖 ssl_client)切换到了 edge 仓库的 1.38.0-r7,并带入 dash 替代 /bin/sh。这是很重的操作(换 C 运行时外壳),演示用 --simulate 全程未落盘。
--repositories-file 与 -X/--repository:不改系统配置临时换源。--repositories-file 整体覆盖仓库列表;-X/--repository 在现有列表之上附加一个仓库。用「仅 main」的临时源文件演示两者配合:
$ printf "https://dl-cdn.alpinelinux.org/alpine/v3.24/main\n" > /tmp/repos-main-only(仅 main 的临时软件源文件)
$ cat /tmp/repos-main-only
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
$ apk add --simulate --repositories-file /tmp/repos-main-only sl(覆盖软件源后 community 不可用)
ERROR: unable to select packages:
sl (no such package):
required by: world[sl]
退出码=1
$ apk add --simulate --repositories-file /tmp/repos-main-only -X https://dl-cdn.alpinelinux.org/alpine/v3.24/community sl(-X 附加 community 后可解析)
(1/1) Installing sl (5.02-r1)
OK: 10.8 MiB in 25 packages
退出码=0
$ apk add --simulate --repositories-file /tmp/repos-main-only tree(main 内的包不受影响)
OK: 10.8 MiB in 24 packages
退出码=0
sl 在 community 仓库:覆盖后报 no such package,-X 附加 community 即解析成功。这两个参数不碰 /etc/apk/repositories,适合一次性验证或脚本内定源。
💡 技术拓展:Alpine 的仓库分支结构(本文实测用 v3.24 的 main + community)——
仓库 内容 签名/维护 main 核心发行集,官方核心团队维护并支持到该版 EOL 官方完整支持 community 社区维护的非核心包(如 htop 以外的桌面、语言栈) 社区构建,跟随版本发布 edge 滚动开发版仓库,包最新但不保证稳定 持续构建,无版本承诺 地址模板
https://dl-cdn.alpinelinux.org/alpine/<分支>/<仓库>:分支填v3.24这类稳定版或edge。国内镜像(TUNA/阿里/中科大)同步全部分支,换源只改域名即可。本文实测「默认用 v3.24 main+community、edge 仅以 @tag 按需引用」。
3.4 apk version 与 apk upgrade:版本比较与全量升级
version 子命令有三种形态:对照已装/可用版本、校验版本号合法性、比较两个版本号。当时的系统有 3 个包可升级(libcrypto3/libssl3/zlib),先看对照输出:
$ apk version
Installed: Available:
libcrypto3-3.5.8-r0 < 3.5.9-r0
libssl3-3.5.8-r0 < 3.5.9-r0
zlib-1.3.2-r0 < 1.3.2-r1
$ apk version -I(各软件仓库索引版本)
v3.24.2-130-g852d1a447f6 [https://dl-cdn.alpinelinux.org/alpine/v3.24/main]
v3.24.2-123-gee0e55516c1 [https://dl-cdn.alpinelinux.org/alpine/v3.24/community]
(升级执行后同样的 apk version 只剩表头两行、无内容行,即「无可升级」;本文后段实测时即是此状态。)
版本号工具集:
$ apk version -c 3.24.2 1.2.3_alpha 1.2(版本号合法性检查)
退出码=0
$ apk version -c "1..2"(非法版本号)
1..2
退出码=1
$ apk version -t 1.2.3 1.2.10(比较两个版本号)
<
退出码=0
$ apk version -t 2.0 2.0
=
退出码=0
$ apk version -t 3.0 2.9
>
退出码=0
$ apk version -l "<"(列出有可升级版本的包)
Installed: Available:
libcrypto3-3.5.8-r0 < 3.5.9-r0
libssl3-3.5.8-r0 < 3.5.9-r0
zlib-1.3.2-r0 < 1.3.2-r1
-t 输出 </=/> 三种关系符,-l "<" 等价于全量 apk version 的可升级视图。
upgrade 把已装包升到仓库最新。先 --simulate 再执行:
$ apk upgrade --simulate
(1/3) Upgrading libcrypto3 (3.5.8-r0 -> 3.5.9-r0)
(2/3) Upgrading libssl3 (3.5.8-r0 -> 3.5.9-r0)
(3/3) Upgrading zlib (1.3.2-r0 -> 1.3.2-r1)
OK: 10.8 MiB in 24 packages
$ apk upgrade
(1/3) Upgrading libcrypto3 (3.5.8-r0 -> 3.5.9-r0)
(2/3) Upgrading libssl3 (3.5.8-r0 -> 3.5.9-r0)
(3/3) Upgrading zlib (1.3.2-r0 -> 1.3.2-r1)
OK: 10.8 MiB in 24 packages
upgrade 的四个策略参数(在无可升级包的基线上全部先 simulate 验证):
$ apk upgrade --available --simulate(-a:全部按当前仓库可用版本重置重算)
OK: 10.0 MiB in 20 packages
$ apk upgrade --ignore zlib --simulate(--ignore:跳过指定包升级其余)
OK: 10.0 MiB in 20 packages
$ apk upgrade --latest --simulate(-l:始终选最新版本)
OK: 10.0 MiB in 20 packages
$ apk upgrade --prune --simulate(--prune:把仓库里已不存在的包从 WORLD 剪掉)
OK: 10.0 MiB in 20 packages
$ apk upgrade --prune(真实执行,WORLD 无失效项则无操作)
OK: 10.0 MiB in 20 packages
语义说明:--available 在换源/降级场景最有用——它不追求「最新」,而是把所有包对齐到「当前仓库里存在的版本」(源里没有的就卸掉);--ignore 排除指定包;--latest 在多仓库同包多版本时强制选最高;--prune 清理 world 里已从仓库消失的包名。
3.5 apk search:按名字或描述搜索
search 对所有仓库索引做大小写不敏感的子串匹配:
$ apk search tree(按子串匹配,共 161 行,节选首尾)
abseil-cpp-dev-20250814.1-r0
agensgraph-contrib-2.16.0-r2
(中间略)
tree-2.3.2-r0
tree-doc-2.3.2-r0
(中间略)
vtk-9.5.2-r2
-v(全局 --verbose):附上描述,-x/--exact 与 -e:精确匹配包名,-d:把描述也纳入匹配,--origin:输出基础包名(origin):
$ apk search -v htop(全局 -v 详细输出)
htop-3.5.3-r0 - Interactive process viewer
htop-doc-3.5.3-r0 - Interactive process viewer (documentation)
netpbm-11.14.0-r0 - Toolkit for manipulation of graphic images
varnish-7.7.3-r0 - High-performance HTTP accelerator
$ apk search -x sl(精确匹配包名)
sl-5.02-r1
$ apk search -e sl(-e 与 -x 等价)
sl-5.02-r1
$ apk search -x tre(精确匹配不命中模糊词)
退出码=1
$ apk search -d "interactive process viewer"(同时搜索描述)
htop-3.5.3-r0
htop-doc-3.5.3-r0
$ apk search --origin htop(按 origin 输出基础包名)
htop-3.5.3-r0
htop-3.5.3-r0
netpbm-11.14.0-r0
varnish-7.7.3-r0
解读:-x 精确匹配无命中时退出码 1,脚本里可用 apk search -x 包名 >/dev/null 判断仓库里是否存在某包;-v 显示的 - 描述 来自包元数据 description 字段;--origin 会把同一 origin 的衍生包(如 netpbm 系)都列出来。
3.6 apk info:已装包详情
info 默认等价 -dws(描述+主页+大小)。逐参数实测:
$ apk info bash(默认等价 -dws)
bash-5.3.9-r1 description:
The GNU Bourne Again shell
bash-5.3.9-r1 webpage:
https://www.gnu.org/software/bash/bash.html
bash-5.3.9-r1 installed size:
1344 KiB
$ apk info -d tree(描述)
tree-2.3.2-r0 description:
Recursive directory indented listing of files
$ apk info -e tree
tree
$ apk info -e sl(未安装时)
退出码=1
$ apk info -R htop(依赖)
htop-3.5.3-r0 depends on:
lsof
so:libc.musl-x86_64.so.1
so:libncursesw.so.6
$ apk info -r htop(反向依赖)
htop-3.5.3-r0 is required by:
$ apk info -s htop(安装大小)
htop-3.5.3-r0 installed size:
307 KiB
$ apk info -w htop(上游主页)
htop-3.5.3-r0 webpage:
https://htop.dev/
$ apk info -L tree(文件清单)
tree-2.3.2-r0 contains:
usr/bin/tree
$ apk info -W /usr/bin/tree(反查文件归属)
/usr/bin/tree is owned by tree-2.3.2-r0
$ apk info -P busybox(provides)
busybox-1.37.0-r31 provides:
cmd:busybox=1.37.0-r31
-a(--all):一次性输出全部已知信息:
$ apk info -a bash(全部已知信息)
bash-5.3.9-r1 description:
The GNU Bourne Again shell
bash-5.3.9-r1 webpage:
https://www.gnu.org/software/bash/bash.html
bash-5.3.9-r1 installed size:
1344 KiB
bash-5.3.9-r1 depends on:
/bin/sh
so:libc.musl-x86_64.so.1
so:libreadline.so.8
bash-5.3.9-r1 provides:
cmd:bash=5.3.9-r1
bash-5.3.9-r1 is required by:
bash-5.3.9-r1 contains:
bin/bash
etc/bash/bashrc
etc/profile.d/00-bashrc.sh
usr/lib/bash/accept
(其余 39 行文件清单略)
bash-5.3.9-r1 triggers:
bash-5.3.9-r1 has auto-install rule:
bash-5.3.9-r1 affects auto-installation of:
bash-5.3.9-r1 replaces:
bash-5.3.9-r1 license:
GPL-3.0-or-later
元数据类小参数:--license(SPDX 许可证)、--install-if(自动安装规则)、--replaces(替换关系)、-t(活动触发器):
$ apk info --license busybox(SPDX 许可证查询)
busybox-1.37.0-r31 license:
GPL-2.0-only
$ apk info --install-if busybox(install_if 规则)
busybox-1.37.0-r31 has auto-install rule:
$ apk info --replaces busybox(replaces 规则)
busybox-1.37.0-r31 replaces:
busybox-initscripts
$ apk info -t busybox-openrc(活动触发器)
busybox-openrc-1.37.0-r31 triggers:
apk-tools 3 移除了 info 的 -o/--origin(2.x 教程里的 apk info -o busybox 已失效):
$ apk info -o busybox(apk2 的 -o/--origin 在 apk3 info 是否仍存在?)
ERROR: command line: unrecognized option 'o'
退出码=1
查 origin 的替代:apk list busybox 输出中花括号里的 {busybox} 就是 origin(3.10 节),或 apk search --origin 包名。
💡 说明:
apk info -e 包名是运维脚本里判断「装没装」的标准姿势——有输出且退出码 0 为已安装,退出码 1 为未安装,比解析apk info全文可靠得多。-W 文件路径则是「这个文件是谁装的」反查入口。
3.7 apk fetch:只下载不安装
fetch 把仓库里的 .apk 文件下载到本地目录,默认下到当前工作目录,-o 指定目录:
$ mkdir -p /tmp/fetchdemo && cd /tmp/fetchdemo
$ apk fetch --simulate htop(模拟下载,只打印将下载的文件)
Downloading htop-3.5.3-r0
$ apk fetch --url bc(打印完整下载 URL)
https://dl-cdn.alpinelinux.org/alpine/v3.24/main/x86_64/bc-1.08.2-r1.apk
$ apk fetch -o /tmp/fetchdemo tree(下载到指定目录)
Downloading tree-2.3.2-r0
$ apk fetch htop(下载到当前目录)
Downloading htop-3.5.3-r0
$ ls -lh /tmp/fetchdemo/
total 228K
-rw-r--r-- 1 root root 54.8K Apr 21 09:45 bc-1.08.2-r1.apk
-rw-r--r-- 1 root root 139.7K Aug 17 00:43 htop-3.5.3-r0.apk
-rw-r--r-- 1 root root 31.7K Apr 21 09:47 tree-2.3.2-r0.apk
$ apk fetch nosuch-pkg(不存在的包)
nosuch-pkg: unable to select package (or its dependencies)
退出码=1
--recursive(-R):连同依赖一起下载——fetch 自身帮助里没有这个参数,它来自所有查询类子命令共享的 Query options(--recursive:用求解器把约束展开成完整包集合),实测 -R 短参可用且确实递归:
$ apk fetch -R -o /tmp/localrepo2/x86_64 htop(-R 短参对含依赖包是否递归?)
Downloading htop-3.5.3-r0
Downloading libncursesw-6.6_p20260516-r0
Downloading lsof-4.99.6-r0
Downloading musl-1.2.6-r2
Downloading ncurses-terminfo-base-6.6_p20260516-r0
$ apk fetch -R -o /tmp/localrepo tree(验证 -R 是否仍是合法短参)
Downloading tree-2.3.2-r0
htop 连带 4 个依赖一次抓全(tree 无依赖故只有 1 行),做离线安装包集合全靠它。fetch 其余专属参数:--stdout/-s 直接把包体吐到标准输出、--link/-l 尽量硬链接省空间、--pkgname-spec 自定义下载文件名格式、--built-after TIMESPEC 只取该时间后构建的包。
3.8 apk cache:本地缓存管理
apk 的包缓存默认未启用——启用方式是把 /etc/apk/cache 做成指向本地目录的符号链接(官方帮助原文:cache 目录不能放在 tmpfs 上)。cache 有四个子命令:clean(清过期包)、purge(清全部)、download(把已装包/指定依赖抓进缓存)、sync(对齐缓存与已装状态):
$ ls -la /var/cache/apk/(索引缓存现状)
total 2988
drwxr-xr-x 1 root root 4096 Oct 16 16:19 .
drwxr-xr-x 1 root root 4096 Sep 17 17:32 ..
-rw-r--r-- 1 root root 528376 Oct 16 16:19 APKINDEX.630cb808.tar.gz
-rw-r--r-- 1 root root 2517553 Oct 16 16:19 APKINDEX.9c5ff2cc.tar.gz
$ apk cache clean(清理缓存)
退出码=0
$ apk cache purge(清空全部缓存)
退出码=0
即使没启用 /etc/apk/cache,/var/cache/apk/ 也存放着索引缓存(两个 APKINDEX.tar.gz),clean/purge 对包文件生效、索引会按需自动重建。
启用缓存并 download:
$ ls -la /etc/apk/ | grep cache(当前未启用本地缓存)
退出码=1
$ apk cache download(未启用缓存目录时:静默无输出但退出码 0)
退出码=0
$ ln -s /var/cache/apk /etc/apk/cache && apk cache download(启用缓存并下载)
Downloading 21 packages...
( 1/21) Downloading alpine-baselayout-data-3.7.2-r1
( 2/21) Downloading musl-1.2.6-r2
( 3/21) Downloading busybox-1.37.0-r31
( 4/21) Downloading busybox-binsh-1.37.0-r31
( 5/21) Downloading alpine-baselayout-3.7.2-r1
( 6/21) Downloading alpine-keys-2.6-r0
( 7/21) Downloading alpine-release-3.24.2-r0
( 8/21) Downloading libcrypto3-3.5.9-r0
( 9/21) Downloading libssl3-3.5.9-r0
(10/21) Downloading ssl_client-1.37.0-r31
(11/21) Downloading zlib-1.3.2-r1
(12/21) Downloading libapk-3.0.8-r0
(13/21) Downloading ca-certificates-bundle-20260909-r0
(14/21) Downloading apk-tools-3.0.8-r0
(15/21) Downloading ncurses-terminfo-base-6.6_p20260516-r0
(16/21) Downloading libncursesw-6.6_p20260516-r0
(17/21) Downloading readline-8.3.3-r1
(18/21) Downloading bash-5.3.9-r1
(19/21) Downloading scanelf-1.3.9-r1
(20/21) Downloading musl-utils-1.2.6-r2
(21/21) Downloading tree-2.3.2-r0
$ apk cache sync --simulate(sync 对齐缓存与已装包)
$ ls /var/cache/apk/ | head -5(缓存中已有 .apk 文件)
APKINDEX.48b9e337.tar.gz
APKINDEX.630cb808.tar.gz
APKINDEX.9c5ff2cc.tar.gz
APKINDEX.a53e92c7.tar.gz
alpine-baselayout-3.7.2-r1.f0fcfdc2.apk
两个易踩的坑都实测在案:未启用缓存目录时 apk cache download 静默无输出退出码 0(看起来成功了实际什么都没下);apk cache v 这个 2.x 时代的写法在 3.x 直接静默退出码 99(无任何错误文本)。
--no-network:禁网操作(全局布尔取反写法)——索引已在本地时,禁网也能刷新元数据视图:
$ apk update --no-network(禁网:仅用本地索引缓存)
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/main]
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/community]
OK: 28668 distinct packages available
收尾还原(清缓存、摘掉缓存目录):
$ apk cache clean && rm /etc/apk/cache(还原:清缓存并摘除缓存目录)
💡 说明:启用缓存的真正收益是「升级后有完整历史包可回退」+「--no-network 离线重装」。文件名带哈希段(如
tree-2.3.2-r0.f0fcfdc2.apk)是 apk 防止不同仓库同名包互相覆盖的设计,2.x 时代是纯名字-版本.apk。
3.9 apk policy:仓库版本策略
policy 回答「这个包哪个仓库有、装的哪版、候选哪版」,按版本升序列出所有来源:
$ apk policy musl(已安装包的策略:仓库来源 + installed/candidate)
musl policy:
1.2.6-r2:
lib/apk/db/installed
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
$ apk policy htop(未安装包:无 installed 行,给出 candidate)
htop policy:
3.5.3-r0:
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
$ apk policy musl busybox(多包一次查询)
busybox policy:
1.37.0-r31:
lib/apk/db/installed
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
musl policy:
1.2.6-r2:
lib/apk/db/installed
https://dl-cdn.alpinelinux.org/alpine/v3.24/main
已安装的包会多一行 lib/apk/db/installed(本地安装库来源);未安装的只有仓库行。换源排障时用它验证「包会从哪个仓库解析」非常直观——3.13 节本地仓库演示里 policy 直接把 /tmp/localrepo2 列为来源。注意:policy 对不存在的包不报错(无输出、退出码 0),脚本判断要用 apk search -x:
$ apk policy nosuch-pkg-demo(不存在的包)
退出码=0
3.10 apk list:按模式列包
list 输出格式比 search 丰富:名字-版本 架构 {origin} (许可证) [状态标记]:
$ apk list tree(按模式列出仓库中的包)
tree-2.3.2-r0 x86_64 {tree} (GPL-2.0-or-later) [installed]
$ apk list "busybox*"(通配模式,节选前 8 行)
busybox-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only) [installed]
busybox-binsh-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only) [installed]
busybox-doc-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only)
busybox-extras-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only)
busybox-extras-openrc-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only)
busybox-ifupdown-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only)
busybox-mdev-openrc-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only)
busybox-openrc-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only)
(共 10 行)
$ apk list --installed(仅已安装,节选前 6 行)
alpine-baselayout-3.7.2-r1 x86_64 {alpine-baselayout} (GPL-2.0-only) [installed]
alpine-baselayout-data-3.7.2-r1 x86_64 {alpine-baselayout} (GPL-2.0-only) [installed]
alpine-keys-2.6-r0 x86_64 {alpine-keys} (MIT) [installed]
alpine-release-3.24.2-r0 x86_64 {alpine-base} (MIT) [installed]
apk-tools-3.0.8-r0 x86_64 {apk-tools} (GPL-2.0-only) [installed]
bash-5.3.9-r1 x86_64 {bash} (GPL-3.0-or-later) [installed]
(共 21 行)
$ apk list --installed bash
bash-5.3.9-r1 x86_64 {bash} (GPL-3.0-or-later) [installed]
$ apk list --upgradable(列出可升级包)
$ apk list --available htop(仅仓库可用包)
htop-3.5.3-r0 x86_64 {htop} (GPL-2.0-or-later)
$ apk list --origin busybox(按 origin 归组列出)
busybox-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only) [installed]
busybox-binsh-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only) [installed]
(中间 8 行略)
ssl_client-1.37.0-r31 x86_64 {busybox} (GPL-2.0-only) [installed]
(共 11 行)
$ apk list --orphaned(孤儿包:无任何包依赖且不在 WORLD)
$ apk list --manifest(name version 两列格式,节选前 5 行)
alpine-baselayout 3.7.2-r1
alpine-baselayout-data 3.7.2-r1
alpine-keys 2.6-r0
alpine-release 3.24.2-r0
apk-tools 3.0.8-r0
$ apk list --providers "so:libc.musl-x86_64.so.1"(谁提供 musl 的 so 依赖)
<so:libc.musl-x86_64.so.1> musl-1.2.6-r2 x86_64 {musl} (MIT) [installed]
专属参数一览(均实测):-I/--installed(只看已装)、-a/--available(只看仓库可用)、-u/--upgradable(可升级,无可升级时为空)、-o/--origin(按基础包归组)、-O/--orphaned(孤儿包)、--manifest(名 版本 两列,适合喂给脚本做对账)、-P/--providers(按提供者查,so:/cmd: 原子加尖括号传入)、-d/--depends(按依赖关系列)。
💡 说明:list 输出行尾的
[installed]标记与花括号{origin}组合起来信息量最大:tree-2.3.2-r0 x86_64 {tree} (GPL-2.0-or-later) [installed]一行读出版本、架构、origin、许可证、安装状态。没有[installed]的行表示仓库里有但本机没装。
3.11 apk query:结构化查询(apk-tools 3 新增)
query 是 3.x 的统一查询入口,输出「字段名: 值」的结构化格式,并支持 yaml/json 输出,天然适合脚本与程序消费:
$ apk query bash(按名字查询包元数据,节选前 12 行)
Name: bash
Version: 5.3.9-r1
Description: The GNU Bourne Again shell
Arch: x86_64
License: GPL-3.0-or-later
Origin: bash
URL: https://www.gnu.org/software/bash/bash.html
File-Size: 480961
$ apk query --format yaml musl(yaml 输出格式)
# 1 items
- name: musl
version: 1.2.6-r2
description: the musl c library (libc) implementation
arch: x86_64
license: MIT
origin: musl
url: https://musl.libc.org/
file-size: 415475
$ apk query --format json musl(json 输出格式,节选前 12 行)
[
{
"name": "musl",
"version": "1.2.6-r2",
"description": "the musl c library (libc) implementation",
"arch": "x86_64",
"license": "MIT",
"origin": "musl",
"url": "https://musl.libc.org/",
"file-size": 415475
}
]
$ apk query --fields name,version musl busybox(指定字段)
Name: busybox
Version: 1.37.0-r31
Name: musl
Version: 1.2.6-r2
过滤与来源控制参数:
$ apk query --world(按 WORLD 约束展开查询全部顶层包)
Name: alpine-baselayout
Version: 3.7.2-r1
Description: Alpine base dir structure and init scripts
Arch: x86_64
License: GPL-2.0-only
Origin: alpine-baselayout
URL: https://gitlab.alpinelinux.org/alpine/aports/-/tree/master/main/alpine-baselayout
File-Size: 8281
(其余 world 内包依次列出,略)
$ apk query --installed musl(--installed 过滤 + 显式约束)
Name: musl
Version: 1.2.6-r2
Description: the musl c library (libc) implementation
Arch: x86_64
License: MIT
Origin: musl
URL: https://musl.libc.org/
File-Size: 415475
$ apk query --from repositories htop(--from repositories:排除本地库仅查仓库)
Name: htop
Version: 3.5.3-r0
Description: Interactive process viewer
Arch: x86_64
License: GPL-2.0-or-later
Origin: htop
URL: https://htop.dev/
File-Size: 143008
$ apk query --upgradable(可升级过滤)
$ apk query --orphaned(孤儿包查询)
两个易误解点实测在案:裸 apk query world 是把 "world" 当包名去匹配(无此包,空输出退出码 0),查 WORLD 必须用过滤参数 --world;--installed 是过滤器不是列举器——不带约束时结果为空,要列举全部已装包用 apk list --installed 或 apk info。--from 可选 system(默认,本地库+仓库)/repositories/installed/none 四种来源。
3.12 apk fix 与 apk audit:修复与巡检
fix 不修改 WORLD,只把已装包修复到与约束一致:默认策略是重装(--reinstall, -r),可选 --upgrade, -u(有升级就升)、--depends, -d(连带修依赖)、--directory-permissions(重置目录权限)、--xattr, -x(修扩展属性)。
先用 audit 制造并定位一个真实损坏场景——注意 apk 3 的 audit 默认只审计配置文件(等价 --backup),审计程序文件必须加 --system:
apk add tree
tree --version | head -1
printf broken > /usr/bin/tree
tree --version
apk audit --system /usr/bin
apk fix tree
tree --version | head -1
apk audit --system /usr/bin
实测回显:
$ tree --version | head -1(文件完好时正常执行)
tree v2.3.2 © 1996 - 2026 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro
$ printf broken > /usr/bin/tree(模拟程序文件损坏)
$ tree --version(损坏后执行失败)
/usr/bin/tree: line 1: broken: command not found
退出码=127
$ apk audit --system /usr/bin(按目录路径审计:U=内容被改动)
U usr/bin/tree
$ apk fix tree(默认策略即重装,恢复损坏文件)
(1/1) Reinstalling tree (2.3.2-r0)
Executing busybox-1.37.0-r31.trigger
OK: 10.1 MiB in 21 packages
$ tree --version | head -1(修复后恢复正常)
tree v2.3.2 © 1996 - 2026 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro
$ apk audit --system /usr/bin(修复后无输出=完好)
audit 的路径写法有讲究(逐个实测):绝对路径有效,相对路径会被跳过并告警,单文件路径退出码 99 不产出结果:
$ apk audit usr/bin(相对根路径形式)
WARNING: usr/bin: relative path skipped.
$ apk audit /usr/bin/tree(直接给文件路径)
退出码=99
audit 全系统巡检与标记含义(U=被改动 Modified、A=包数据库之外新增的文件 Added):
$ apk audit(全系统巡检,节选前 5 行)
U etc/shadow
A etc/apk/arch
A etc/apk/repositories
A etc/apk/keys/alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
A etc/apk/keys/alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub
(共 19 行)
U etc/shadow 是因为 root 密码项与包初始模板不同(正常运维痕迹);A etc/apk/* 是包数据库之外的本地配置。audit 其余专属参数:--full(等同 --system 再加报告全部新增目录/文件)、--packages(只打印受影响包名)、--check-permissions(连权限一起查)、--ignore-busybox-symlinks(忽略指向 busybox 的符号链接——Alpine 里大量命令是 busybox 链接,默认会产生海量 A 记录)。
fix 的其余形态(基线上均为无操作):
$ apk fix --directory-permissions --simulate(重置目录权限)
OK: 10.1 MiB in 21 packages
$ apk fix --upgrade --simulate(fix -u:对指定包走升级策略)
OK: 10.1 MiB in 21 packages
$ apk fix --simulate(修复检查)
OK: 10.8 MiB in 24 packages
3.13 apk index 与 apk mkndx:搭建本地仓库
自建仓库三步:收集 .apk 文件 → 生成索引 → 客户端挂仓库。目录布局有硬性要求:仓库根下必须有 <arch>/APKINDEX 结构,先收集包(用 3.7 节的 fetch -R):
$ apk fetch -R -o /tmp/localrepo2/x86_64 htop(-R 连依赖下载到仓库架构子目录)
Downloading htop-3.5.3-r0
Downloading libncursesw-6.6_p20260516-r0
Downloading lsof-4.99.6-r0
Downloading musl-1.2.6-r2
Downloading ncurses-terminfo-base-6.6_p20260516-r0
$ apk fetch -R -o /tmp/localrepo tree(验证 -R 是否仍是合法短参)
Downloading tree-2.3.2-r0
生成 v2 索引(apk index),在 x86_64 子目录内执行:
$ cd /tmp/localrepo2/x86_64
$ apk index -o APKINDEX.tar.gz *.apk(在 x86_64 子目录内生成索引)
Index has 5 packages (of which 5 are new)
index 专属参数:-o/--output(输出文件)、-d/--description(索引描述)、-x/--index(读旧索引加速增量重建)、--merge(合并进现有索引)、--prune-origin(合并时剪掉同 origin 旧包)、--rewrite-arch(改写架构字段)。
客户端挂载与信任验证——未签名索引会被拒绝,这正是 --allow-untrusted 的用武之地:
$ echo /tmp/localrepo2 > /tmp/onlylocal(构造"仅本地仓库"源文件)
/tmp/localrepo2
$ apk add --simulate --repositories-file /tmp/onlylocal htop(未签名索引 → 拒绝)
WARNING: opening /tmp/localrepo2/x86_64/APKINDEX.tar.gz: UNTRUSTED signature
ERROR: unable to select packages:
htop (no such package):
required by: world[htop]
$ apk add --simulate --allow-untrusted --repositories-file /tmp/onlylocal htop(--allow-untrusted 放行本地仓库)
(1/2) Installing lsof (4.99.6-r0)
(2/2) Installing htop (3.5.3-r0)
OK: 10.7 MiB in 23 packages
$ apk policy --allow-untrusted --repositories-file /tmp/onlylocal htop(本地仓库中的 htop 版本)
htop policy:
3.5.3-r0:
/tmp/localrepo2
policy 输出确认包确实解析自 /tmp/localrepo2 本地仓库。注意首轮实验踩过的坑:把 .apk 与 APKINDEX 平铺在仓库根目录(不做 x86_64 子目录)时,apk 会去找 仓库根/x86_64/APKINDEX.tar.gz,找不到只打 WARNING 然后回落到正式仓库解析——不仅本地仓库没生效,还容易误以为装的是本地包:
$ apk add --simulate -X /tmp/localrepo bc(无 --allow-untrusted:未签名索引被拒)
WARNING: opening /tmp/localrepo/x86_64/APKINDEX.tar.gz: No such file or directory
(1/1) Installing bc (1.08.2-r1)
OK: 10.2 MiB in 22 packages
(此输出中的 bc 实际来自 dl-cdn 正式仓库——布局错误时 WARNING 是唯一线索。)
v3 索引(mkndx)与完整性工具——换到 3.7 节演示用的 /tmp/localrepo 目录(含 tree 共 6 个包)生成 v3 索引:
$ apk mkndx --output APKINDEX3.ndx *.apk(生成 v3 索引)
Index has 6 packages (of which 6 are new)
$ ls -la /tmp/localrepo/(两种索引并存)
total 872
drwxr-xr-x 2 root root 4096 Oct 17 00:14 .
drwxrwxrwt 1 root root 4096 Oct 17 00:14 ..
-rw-r--r-- 1 root root 1090 Oct 17 00:14 APKINDEX.tar.gz
-rw-r--r-- 1 root root 1228 Oct 17 00:14 APKINDEX3.ndx
-rw-r--r-- 1 root root 143008 Aug 17 00:43 htop-3.5.3-r0.apk
-rw-r--r-- 1 root root 159438 May 24 08:53 libncursesw-6.6_p20260516-r0.apk
-rw-r--r-- 1 root root 94899 Apr 21 09:46 lsof-4.99.6-r0.apk
-rw-r--r-- 1 root root 415475 Apr 21 09:47 musl-1.2.6-r2.apk
-rw-r--r-- 1 root root 22172 May 24 08:53 ncurses-terminfo-base-6.6_p20260516-r0.apk
-rw-r--r-- 1 root root 32419 Apr 21 09:47 tree-2.3.2-r0.apk
verify 与 manifest 是配套的完整性工具——verify 校验签名与哈希(未签名索引返回 UNTRUSTED 且退出码 1),manifest 逐文件列校验和:
$ apk verify /tmp/localrepo/tree-*.apk(校验包完整性:包本身有官方签名)
/tmp/localrepo/tree-2.3.2-r0.apk: OK
$ apk verify /tmp/localrepo/APKINDEX.tar.gz(校验索引:未签名)
/tmp/localrepo/APKINDEX.tar.gz: UNTRUSTED signature
退出码=1
$ apk manifest /tmp/localrepo/tree-*.apk(列出包内文件校验和,节选前 5 行)
sha1:aa5e6e7c642fc6b8e1e6c75a3192c302e4608a15 usr/bin/tree
$ apk verify(校验全部已装包完整性,节选前 4 行)
💡 技术拓展:apk 的两代仓库索引格式对比(本文实测两套都能生成)——
格式 生成命令 载体 特点 v2(APKINDEX) apk indextar.gz(内含 APKINDEX 文本) 全系 apk 兼容,生态最广,逐字段文本 v3(ndx/adb) apk mkndx二进制 adb 格式 apk-tools 3 原生,支持哈希完整性字段、更省空间 本文本地仓库实测用 v2(
apk index):兼容性最好;v3 索引配合adbsign签名后可在 3.x 上获得更强的完整性保证。生产自建源建议 v2 索引 + abuild-sign 私钥签名,避免 --allow-untrusted 常开。
3.14 --keys-dir 与 --allow-untrusted:信任控制
apk 校验链是「索引签名 + 包签名都要过信任密钥」。把信任目录指向空目录,可以让任何包都「不受信」,从而完整演示 --allow-untrusted 的放行行为:
$ apk add --simulate --keys-dir /tmp/emptykeys /tmp/pkgdl/tree-*.apk(空信任密钥目录 → 拒签)
WARNING: opening from cache https://dl-cdn.alpinelinux.org/alpine/v3.24/main/x86_64/APKINDEX.tar.gz: UNTRUSTED signature
WARNING: opening from cache https://dl-cdn.alpinelinux.org/alpine/v3.24/community/x86_64/APKINDEX.tar.gz: UNTRUSTED signature
ERROR: /tmp/pkgdl/tree-2.3.2-r0.apk: UNTRUSTED signature
退出码=99
$ apk add --simulate --allow-untrusted --keys-dir /tmp/emptykeys /tmp/pkgdl/tree-*.apk(--allow-untrusted 放行)
OK: 10.1 MiB in 21 packages
三点解读:索引与包文件分别报 UNTRUSTED(两条 WARNING 加一条 ERROR);此时退出码是 99 而非 1;--allow-untrusted 一次性放行全部信任校验。对比 3.1 节用默认密钥目录装同一文件全程 OK——说明包本身签名正常,问题只出在信任锚(密钥目录)。
⚠️ 注意:
--allow-untrusted会跳过签名校验,等于关闭 apk 的核心安全机制。仅在两种场景使用:① 自建本地仓库尚未签名(配合固定路径源);② 离线环境安装经人工核验的包。任何连公网的生产系统都不应常态化使用。
3.15 --root 与 --initdb:独立根(chroot/救援盘场景)
--root, -p ROOT 把指定目录当系统根操作,--initdb 在该根里初始化全新包数据库——两者组合就是「往一个空目录里装出一个 Alpine」。先准备最小骨架(信任密钥与仓库配置都要放进新根):
$ rm -rf /tmp/newroot && mkdir -p /tmp/newroot/etc/apk/keys(准备最小根目录)
alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub
alpine-devel@lists.alpinelinux.org-6165ee59.rsa.pub
$ apk add --root /tmp/newroot --initdb busybox alpine-baselayout(在独立根初始化包数据库并安装)
(1/5) Installing alpine-baselayout-data (3.7.2-r1)
(2/5) Installing musl (1.2.6-r2)
(3/5) Installing busybox (1.37.0-r31)
Executing busybox-1.37.0-r31.post-install
(4/5) Installing busybox-binsh (1.37.0-r31)
(5/5) Installing alpine-baselayout (3.7.2-r1)
Executing alpine-baselayout-3.7.2-r1.pre-install
Executing alpine-baselayout-3.7.2-r1.post-install
Executing busybox-1.37.0-r31.trigger
OK: 1474 KiB in 5 packages
新根的 WORLD、目录树、包库、统计、升级操作全部可用 --root 视角查看:
$ cat /tmp/newroot/etc/apk/world(新根的 WORLD)
alpine-baselayout
busybox
$ ls /tmp/newroot/(新根目录内容)
bin
dev
etc
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
$ apk info --root /tmp/newroot(查询新根已装包)
alpine-baselayout
alpine-baselayout-data
busybox
busybox-binsh
musl
$ apk stats --root /tmp/newroot(新根统计)
installed:
packages: 5
dirs: 73
files: 38
bytes: 1509379
triggers: 1
available:
names: 70498
packages: 28668
atoms:
num: 60812
$ apk upgrade --root /tmp/newroot --simulate(对新根做升级模拟)
OK: 1474 KiB in 5 packages
这是制作救援环境、构建最小根文件系统、给另一块盘预装系统的标准做法:所有 apk 子命令 都能挂 --root,包安装脚本也在新根内以 chroot 方式执行(可用 --force-no-chroot 关闭)。
3.16 常用全局参数速测
前面各节已实测的全局参数之外,再补三个高频项:
$ apk --print-arch(架构)
x86_64
$ apk -V(版本短参,与 --version 等价)
apk-tools 3.0.8-r0, compiled for x86_64.
$ apk update --no-network(禁网取反写法,3.8 节已详解)
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/main]
v3.24.2-153-gf688430cdb9 [https://dl-cdn.alpinelinux.org/alpine/v3.24/community]
OK: 28668 distinct packages available
dot 子命令(把依赖关系渲染成 graphviz 图)作为查询类命令的补充,一并实测:
$ apk dot busybox(graphviz 依赖图,全部输出)
digraph "apkindex" {
rankdir=LR;
node [shape=box];
"busybox-1.37.0-r31" -> "musl-1.2.6-r2"[arrowhead=inv,label="so:libc.musl-x86_64.so.1",];
}
输出可直接交给 dot -Tsvg 渲染成依赖关系图;专属参数只有 --errors(只画有错误的包)。
四、实战示例
4.1 新机初始化:换国内源并全量升级
cp /etc/apk/repositories /tmp/repositories.bak
sed -i "s|dl-cdn.alpinelinux.org|mirrors.tuna.tsinghua.edu.cn|g" /etc/apk/repositories
apk update
apk upgrade
apk version
换源、刷新、升级、复核四步,全部命令与逐行回显见 3.3 与 3.4 节实测。验证点:apk update 输出行应显示新镜像域名与 OK: N distinct packages available。
4.2 编译环境用完即删:--virtual 包束
apk add --virtual builddeps gcc musl-dev make
# 此处执行编译业务代码等临时任务
apk del builddeps
装包、删包各一条命令,gcc/make 及其全部依赖一次性进出,不污染 WORLD。完整机制与回显见 3.1 节 --virtual 实测;删除后用 apk info -e gcc 验证退出码 1(已不存在)。
4.3 离线安装:fetch -R 抓全依赖后本地装包
联网机器上抓包集合:
mkdir -p /tmp/offline/x86_64 && cd /tmp/offline/x86_64
apk fetch -R -o . htop
apk index -o APKINDEX.tar.gz *.apk
离线机器上安装(本例同机演示,离线机把 /tmp/offline 换成 U 盘挂载点即可):
echo /tmp/offline > /tmp/offline.repo
apk add --repositories-file /tmp/offline.repo --allow-untrusted htop
apk verify /tmp/offline/x86_64/htop-*.apk
未签名索引必须带 --allow-untrusted(3.13/3.14 节实测了被拒与放行的完整回显);若对包集合做过 abuild-sign 签名,则去掉该参数、把公钥放入目标机 /etc/apk/keys/。验证点:apk verify 包名.apk 输出 : OK,apk policy htop 来源行显示离线仓库路径。
4.4 构建最小 Alpine 根文件系统(chroot)
rm -rf /tmp/newroot && mkdir -p /tmp/newroot/etc/apk/keys
cp /etc/apk/keys/* /tmp/newroot/etc/apk/keys/
cp /etc/apk/repositories /tmp/newroot/etc/apk/repositories
apk add --root /tmp/newroot --initdb busybox alpine-baselayout
apk info --root /tmp/newroot
chroot /tmp/newroot /bin/sh
前四步的全部真实回显见 3.15 节实测;最后一步 chroot 进入后即为纯 busybox 环境(exit 退出)。构建救援盘、最小根文件系统、为另一块盘预装系统均以此骨架扩展。
4.5 程序文件损坏急救:audit 定位 + fix 重装
apk audit --system /usr/bin # U 开头行即被改动文件
apk fix tree # 重装受影响包(默认策略即重装)
apk audit --system /usr/bin # 复核:应无输出
完整「损坏 → 执行报错 → audit 检出 U → fix Reinstalling → 恢复」全流程回显见 3.12 节。若不确定包名,用 apk info -W /可疑文件路径 反查归属(3.6 节实测)。
五、注意事项与常见问题
5.1 apk-tools 2.x 教程命令在 3.x 上的失效对照
| 旧命令(2.x) | 3.x 实测结果 | 替代做法 |
|---|---|---|
apk info -o 包名 | ERROR: unrecognized option 'o',退出码 1 | apk list 包名 看 {origin} 字段 |
apk cache v | 静默退出码 99,无任何输出 | 用 apk cache download |
apk fetch -R | 仍可用(-R 短参保留) | 或写全 --recursive |
apk add --no-cache | 仍可用(布尔取反语法) | 或写全 --cache=false |
apk search -v | 仍可用,但 -v 实为全局 verbose 参数 | 语义一致(附描述),无需改 |
apk version -c/-t/-l | 全部可用 | 无需改 |
判断代次看 apk --version 首词:apk-tools 3.x 走本文,2.x 走旧教程。
5.2 UNTRUSTED signature 的三种场景与处置
实测到的三种触发(各有独立回显):
- 索引未签名(自建仓库未
abuild-sign):WARNING: opening /仓库/x86_64/APKINDEX.tar.gz: UNTRUSTED signature+ERROR: unable to select packages:(3.13 节); - 信任密钥缺失(--keys-dir 指向空目录/新根未拷密钥):索引与包文件分别报 UNTRUSTED WARNING/ERROR,退出码 99(3.14 节);
- 对未签名索引 verify:
APKINDEX.tar.gz: UNTRUSTED signature,退出码 1(3.13 节)。
处置:临时放行加 --allow-untrusted(理解风险);根治是给自建源签名(abuild-sign 生成 RSA 签名,公钥分发到各机 /etc/apk/keys/)。
5.3 「World updated, but the following packages are not removed due to:」
apk del 提示该行不是错误:它列出的包因仍被其他顶层包依赖而保留在系统里(3.2 节 lsof: htop 实例)。确认要连依赖一起删时用 apk del --rdepends 包名,或先删依赖方再删被依赖方。
5.4 退出码速查
| 退出码 | 实测场景 |
|---|---|
| 0 | 正常完成,包括 del 未安装包、policy 不存在的包等「静默无操作」 |
| 1 | 求解失败(no such package)、精确搜索无命中、verify 校验失败 |
| 99 | 信任校验失败(--keys-dir 空目录装包)、audit 传入单文件路径等参数级错误 |
| 127 | 被损坏的可执行文件无法运行(/usr/bin/tree: line 1: broken: command not found) |
脚本判断 apk 操作成败不能只看「有无输出」,要显式取 $?。
5.5 本地仓库布局坑:x86_64 子目录必须有
仓库根下必须存在 <arch>/APKINDEX.tar.gz(或 v3 索引),平铺布局会让 apk 只打一句 WARNING: opening /tmp/localrepo/x86_64/APKINDEX.tar.gz: No such file or directory 然后静默回落正式仓库——表面装包成功,实际没走本地源(3.13 节实测对照)。核对方法:apk policy 包名 看来源行是否为本地路径。
5.6 缓存相关两个静默行为
未启用 /etc/apk/cache(符号链接)时:apk cache download 无输出退出码 0(什么都没发生);apk cache v 在 3.x 静默退出码 99。启用方法与 download 全流程回显见 3.8 节。索引缓存(/var/cache/apk/APKINDEX.*.tar.gz)与包缓存相互独立,apk cache clean 不清索引、索引由 apk 按缓存时长(默认策略)自动维护,-U/--update-cache 可强制即时刷新。
5.7 world 文件与依赖的自动清理语义
/etc/apk/world 可以手工编辑(一行一个约束,支持 包名<版本 比较符),但改完必须跑 apk fix(或任意 add/del)让求解器对账,直接改完不提交会出现「world 与实际不一致」。日常装卸一律走 apk add/del:del 即时自动清依赖,没有也不需要 autoremove。删除前想预览会动哪些包,apk del --simulate 包名 先看一遍(3.1 节 --simulate 实测)。
5.8 musl 环境的兼容性提示
Alpine 用 musl 而非 glibc:第三方闭源二进制(多为 glibc 动态链接)直接拷进来通常报 Not found(动态链接器路径不同)或缺 so: 依赖。排查顺序:apk info -R 包名 看依赖原子 → apk search "so:库名" 找提供者(3.10 节 --providers 实测)→ 无 musl 版本时用 apk search gcompat 安装 glibc 兼容层。脚本类依赖优先 cmd: 原子(如 /bin/sh 由 busybox 或 bash 提供)。
5.9 audit 默认只查配置文件
apk 3 的 apk audit 裸跑等价 --backup(仅配置文件),程序文件改动不会出现在结果里——必须 apk audit --system 路径(绝对路径,相对路径被跳过并告警)。全量巡检用 apk audit --full,只想看受影响包名用 --packages(3.12 节全部实测)。
5.10 policy 对不存在的包静默返回
apk policy 不存在的包 无输出且退出码 0(3.9 节实测),脚本里判断「仓库里有没有这个包」应使用 apk search -x 包名(退出码 0/1 可靠区分)。
六、参考链接
- apk-tools 官方源码仓库:https://gitlab.alpinelinux.org/alpine/apk-tools
- Alpine Wiki 包管理总览(apk):https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management
- apk-world(5) WORLD 文件说明:https://wiki.alpinelinux.org/wiki/Apk_world
- 本机手册页:
man 8 apk、man 8 apk-add、man 8 apk-del、man 8 apk-repositories、man 8 apk-world(每个子命令均有对应 man 页,apk 子命令 --help尾行有指引) - 清华 TUNA 镜像 Alpine 帮助页(换源参考):https://mirrors.tuna.tsinghua.edu.cn/help/alpine/
- Alpine 官方下载与镜像列表:https://alpinelinux.org/downloads/