dnf 命令详解与参数实测(Fedora 44)

在 Fedora 44(dnf5 5.4.3.0)上逐项实测 dnf 的安装卸载升级降级、查询反查、软件组、历史回滚、仓库配置与常用全局选项,回显逐字可复现。

Linux命令Linux系统Fedora命令行包管理2026/10/17

dnf 命令详解与参数实测(Fedora 44)

目标:系统掌握 Fedora 上 dnf 的日常包管理操作——元数据缓存、查询与反查、安装/卸载/升级/重装/降级、按包下载、软件组、事务历史与撤销回滚、仓库启用禁用与新增,以及高频全局选项。全文所有命令与回显均在 Fedora 44(dnf5 5.4.3.0,x86_64)上真实执行并逐字记录,退出码一并给出,可直接照搬复现。

一、环境信息

本章先固化实测环境,后文所有回显都基于该环境。验证手段:cat /etc/os-release 与 dnf --version 两条命令即可复验版本,任何人照做都应得到一致结果。

$ grep -E '^(NAME|ID|VERSION_ID|SUPPORT_END)=' /etc/os-release
NAME="Fedora Linux"
ID=fedora
VERSION_ID=44
SUPPORT_END=2027-05-19
项目实测值
发行版Fedora Linux 44(官方支持期至 2027-05-19)
架构x86_64
dnf 实现dnf5(/usr/bin/dnf 是指向 dnf5 的符号链接)
dnf5 版本5.4.3.0(软件包 dnf5-5.4.3.0-2.fc44)
libdnf55.4.3.0(软件包 libdnf5-5.4.3.0-2.fc44)
RPM6.0.2-1.fc44
基线已装包数147(rpm -qa | wc -l)
默认启用仓库fedora、fedora-cisco-openh264、updates
$ dnf --version
dnf5 version 5.4.3.0
dnf5 plugin API version 2.0
libdnf5 version 5.4.3.0
libdnf5 plugin API version 2.2

Loaded dnf5 plugins:
  name: builddep
  version: 1.0.0
  API version: 2.0

  name: changelog
  version: 1.0.0
  API version: 2.0

  name: config-manager
  version: 0.1.0
  API version: 2.0

  name: copr
  version: 0.1.0
  API version: 2.0

  name: needs_restarting
  version: 1.0.0
  API version: 2.0

  name: repoclosure
  version: 1.0.0
  API version: 2.0

  name: repomanage
  version: 1.0.0
  API version: 2.0

  name: reposync
  version: 1.0.0
  API version: 2.0

命令本体与配置文件:

$ ls -l /usr/bin/dnf
lrwxrwxrwx 1 root root 4 Aug 19 00:00 /usr/bin/dnf -> dnf5

$ cat /etc/dnf/dnf.conf
# see `man dnf.conf` for defaults and possible options

[main]
tsflags=nodocs

对上表与回显的解读:

  1. Fedora 41 起,dnf 命令由新一代实现 dnf5 承担,dnf --version 直接输出 dnf5 version,rpm -qf /usr/bin/dnf 返回 dnf5-5.4.3.0-2.fc44,说明"dnf"这个名字在 Fedora 44 上就是 dnf5。
  2. tsflags=nodocs 是 Fedora 官方最小化镜像的默认配置:安装软件包时不带 man 手册和 texinfo 文档。后文回显里 Download size、Installed size 都是在该配置下测得的,数值会比桌面版安装略小,属于正常现象。
  3. Loaded dnf5 plugins 列出的 builddep、changelog、config-manager、copr 等是随主包附带的官方插件,它们各自贡献若干子命令(如 dnf config-manager、dnf changelog),后文都会实测到。

💡 dnf5、dnf4、yum、apt 是什么关系:yum 是 RHEL/CentOS 57 时代的 Python 实现,进入 EOL;dnf4 是 Fedora 2240 与 RHEL 8/9 的默认实现(Python + libdnf/librepo,依赖解析用 libsolv);dnf5 是 C++ 重写版(libdnf5),命令行行为大体兼容但有明确差异,Fedora 41 起成为默认,RHEL 10 同样采用。apt 是 Debian/Ubuntu 体系的包管理器,与 RPM 系无直接血缘。本文实测中撞到的典型差异包括:config-manager --set-enabled 在 dnf5 已移除(改为 config-manager enable 子命令)、dnf help 子命令不存在、history 新增 store/replay、config-manager setopt 的持久化落在 /etc/dnf/repos.override.d/ 覆盖层而不是直接改 .repo 文件——这些都会在对应小节用实测回显展开。依赖解析器方面:yum3 早期是自研求解器,dnf4 与 dnf5 都基于 SAT 求解器 libsolv,apt 则是自家的 APT 求解器,因此"同一组包在 dnf 与 apt 下解出的安装集合不同"是正常现象。本文全部实测基于 dnf5。

二、命令概览(--help 全量回显 + 测试数据准备)

不翻手册时,dnf --help 是最快的入口。dnf5 没有 dnf help 子命令(实测见 3.13 与 FAQ),所以看子命令帮助一律用 dnf <子命令> --help。本章给出 dnf --help 的全量回显并逐块解读,然后准备全文共用的测试数据。

2.1 dnf --help 全量回显

$ dnf --help
Usage:
  dnf5 [GLOBAL OPTIONS] <COMMAND> ...

Description:
  DNF5 is a program for maintaining packages.

Software Management Commands:
  do                                     Do transaction
  install                                Install software
  upgrade                                Upgrade software
  remove                                 Remove (uninstall) software
  distro-sync                            Upgrade or downgrade installed software to the latest available versions
  downgrade                              Downgrade software
  reinstall                              Reinstall software
  debuginfo-install                      Install debuginfo packages.
  swap                                   Remove software and install another in one transaction
  mark                                   Change the reason of an installed package
  autoremove                             Remove all unneeded packages originally installed as dependencies.
  provides                               Find what package provides the given value
  replay                                 Replay a transaction that was previously stored to a directory
  check-upgrade                          Check for available package upgrades
  check                                  Check for problems in the packagedb

Query Commands:
  leaves                                 List groups of installed packages not required by other installed packages
  repoquery                              Search for packages matching various criteria
  search                                 Search for software matching all specified strings
  list                                   Lists packages depending on the packages' relation to the system
  info                                   Lists packages depending on the packages' relation to the system with additional details

Subcommands:
  group                                  Manage comps groups
  environment                            Manage comps environments
  module                                 Manage modules
  history                                Manage transaction history
  repo                                   Manage repositories
  advisory                               Manage advisories
  versionlock                            Manage versionlock configuration
  system-upgrade                         Prepare system for upgrade to a new release
  offline-distrosync                     Store a distro-sync transaction to be performed offline
  offline-upgrade                        Store an upgrade transaction to be performed offline
  offline                                Manage offline transactions
  config-manager                         Manage configuration

Compatibility Aliases:
  check-update                           Alias for 'check-upgrade'
  dg                                     Alias for 'downgrade'
  dsync                                  Alias for 'distro-sync'
  grp                                    Alias for 'group'
  if                                     Alias for 'info'
  in                                     Alias for 'install'
  ls                                     Alias for 'list'
  mc                                     Alias for 'makecache'
  rei                                    Alias for 'reinstall'
  repoinfo                               Alias for 'repo info'
  repolist                               Alias for 'repo list'
  rm                                     Alias for 'remove'
  rq                                     Alias for 'repoquery'
  se                                     Alias for 'search'
  up                                     Alias for 'upgrade'
  update                                 Alias for 'upgrade'
  updateinfo                             Alias for 'advisory'
  upgrade-minimal                        Alias for 'upgrade --minimal'

Commands:
  clean                                  Remove or expire cached data
  download                               Download software to the current directory
  makecache                              Generate the metadata cache
  builddep                               Install build dependencies for package or spec file
  changelog                              Show package changelogs
  copr                                   Manage Copr repositories (add-ons provided by users/community/third-party)
  needs-restarting                       Determine whether system or systemd services need restarting
  repoclosure                            Print list of unresolved dependencies for repositories
  repomanage                             Manage a directory with repodata or with rpm packages
  reposync                               Synchronize a remote DNF repository to a local directory.
  build-dep                              Compatibility alias for 'builddep'

Global options:
  -h, --help                             Print help
  --config=CONFIG_FILE_PATH              Configuration file location
  -q, --quiet                            In combination with a non-interactive command, shows just the relevant content. Suppresses messages notifying about the current state or actions of dnf5.
  -C, --cacheonly                        Run entirely from system cache, don't update the cache and use it even in case it is expired.
  --color=COLOR                          Control whether color is used.
  --refresh                              Force refreshing metadata before running the command.
  --repofrompath=REPO_ID,REPO_PATH       create additional repository using id and path
  --setopt=[REPO_ID.]OPTION=VALUE        set arbitrary config and repo options
  --setvar=VAR_NAME=VALUE                set arbitrary variable
  -y, --assumeyes                        automatically answer yes for all questions
  --assumeno                             automatically answer no for all questions
  --best                                 try the best available package versions in transactions
  --no-best                              do not limit the transaction to the best candidate
  --allow-vendor-change                  allow automatic package replacements from different vendors
  --no-allow-vendor-change               do not allow automatic package replacements from different vendors
  --no-docs                              Don't install files that are marked as documentation (which includes man pages and texinfo documents)
  -x package,..., --exclude=package,...  exclude packages by name or glob
  --enable-repo=REPO_ID,...              Enable additional repositories. List option. Supports globs, can be specified multiple times.
  --disable-repo=REPO_ID,...             Disable repositories. List option. Supports globs, can be specified multiple times.
  --repo=REPO_ID,...                     Enable just specific repositories. List option. Supports globs, can be specified multiple times.
  --no-gpgchecks                         disable OpenPGP signature checking (if RPM policy allows)
  --no-plugins                           Disable all libdnf5 plugins
  --enable-plugin=PLUGIN_NAME,...        Enable libdnf5 plugins by name. List option. Supports globs, can be specified multiple times.
  --disable-plugin=PLUGIN_NAME,...       Disable libdnf5 plugins by name. List option. Supports globs, can be specified multiple times.
  --comment=COMMENT                      add a comment to transaction
  --installroot=ABSOLUTE_PATH            set install root
  --use-host-config                      use configuration, reposdir, and vars from the host system rather than the installroot
  --releasever=RELEASEVER                override the value of $releasever in config and repo files
  --releasever-major=RELEASEVER_MAJOR    override the value of $releasever_major in config and repo files
  --releasever-minor=RELEASEVER_MINOR    override the value of $releasever_minor in config and repo files
  --show-new-leaves                      Show newly installed leaf packages and packages that became leaves after a transaction.
  --debugsolver                          Dump detailed solving results into files
  --dump-main-config                     Print main configuration values to stdout
  --dump-repo-config=REPO_ID,...         Print repository configuration values to stdout. List option. Supports globs
  --dump-variables                       Print variable values to stdout
  --version                              Show DNF5 version and exit
  --forcearch=FORCEARCH                  Force the use of a different architecture.
  --skip-file-locks                      Skip acquiring file locks, such as the lock on the system repository

Options Compatibility aliases:
  -c CONFIG_FILE_PATH                    Alias for '--config'
  --nobest                               Alias for '--no-best'
  --nodocs                               Alias for '--no-docs'
  --enablerepo=REPO_ID,...               Alias for '--enable-repo'
  --disablerepo=REPO_ID,...              Alias for '--disable-repo'
  --repoid=REPO_ID,...                   Alias for '--repo'
  --nogpgcheck                           Alias for '--no-gpgchecks'
  --noplugins                            Alias for '--no-plugins'
  --enableplugin=PLUGIN_NAME,...         Alias for '--enable-plugin'
  --disableplugin=PLUGIN_NAME,...        Alias for '--disable-plugin'

2.2 回显解读

命令分组。dnf5 把子命令分为五类:Software Management Commands 是会真实改动系统的事务类命令(install/upgrade/remove/downgrade/reinstall/autoremove/swap/distro-sync…);Query Commands 是只读查询(search/info/list/provides/repoquery/leaves);Subcommands 是需要再跟一层子命令的入口(group/history/repo/config-manager…);Commands 是独立工具型命令(clean/makecache/download/changelog…);Compatibility Aliases 是短别名表。日常运维最高频的三十来个命令全部覆盖在本文第三章。

别名表值得专门一读:in=install、up=upgrade、rm=remove、se=search、ls=list、if=info、mc=makecache、rq=repoquery、rei=reinstall、dg=downgrade、dsync=distro-sync、grp=group。另有两条语义级别名:check-update 实际是 check-upgrade(后者才是本名),update 实际是 upgrade——这就是为什么老脚本里 dnf update 和 dnf upgrade 等价。repoinfo/repolist 则是 repo info/repo list 的扁平别名。

全局选项Compat表。末尾的 Options Compatibility aliases 是 dnf4 风格选项到 dnf5 风格的映射:--enablerepo/--disablerepo 对应新写法 --enable-repo/--disable-repo,--nogpgcheck 对应 --no-gpgchecks。老脚本不用改也能跑,但写新脚本建议统一用 dnf5 原生拼写。

💡 子命令帮助的两种姿势:dnf4 时代 dnf help install 与 dnf install --help 都能看帮助;dnf5 只保留了后者,dnf help install 会报 Unknown argument "help" for command "dnf5"(实测退出码 2,见 3.13)。排查子命令报错时先确认你查的是 dnf5 帮助文档(man dnf5),别拿 dnf4 的 man dnf 对照。

2.3 测试数据准备

全文演示围绕以下对象展开,先建工作目录:

mkdir -p /root/demo/dnf && cd /root/demo/dnf
演示对象用途特点
tree单文件小工具,装/卸/重装/降级演示几乎无依赖,回显干净
cowsay依赖解析演示连带拉起 60 余个 Perl 依赖,最能看出事务结构
figlet、sl历史撤销演示两个互相独立的小包,方便逐条 undo
fonts 软件组隐藏组与组安装演示Uservisible: no,安装后不显示在默认组列表
createrepo_c自建本地仓库生成 repodata 元数据

验证手段约定:每个事务命令执行后用 rpm -q <包名> 或 dnf list --installed <包名> 复核,关键命令补记 $? 退出码;凡涉及网络下载的回显,速率与已用时间是当时网络状况的真实记录,复现时数值不同属正常,文本内容应当一致。

三、参数逐项实测

本章按"缓存 → 查询 → 反查 → 安装卸载 → 升级降级重装 → 下载 → 软件组 → 历史 → 仓库配置 → 全局选项"的顺序逐项实测。每个参数给出:引导说明、实测命令、逐字回显、行为解读。所有命令以 root 身份在系统默认源下执行。

3.1 makecache:生成元数据缓存

makecache 把各仓库的 repodata(主索引、文件清单、其他信息三类 XML,dnf5 下为 zstd 压缩)下载到本地 /var/cache/libdnf5/,后续查询与事务都读缓存,避免每次联网。Fedora 各仓库的 metadata_expire 不同(fedora 7 天、updates 6 小时),所以 makecache 是否真的下载取决于缓存是否过期——实测正好能看到两种情况。

$ dnf makecache
Updating and loading repositories:
 Fedora 44 - x86_64 - Updates           100% |  18.9 KiB/s |   8.2 KiB |  00m00s
Repositories loaded.
Metadata cache created.
$ echo $?
0

这次只有 updates 重新下载(8.2 KiB,仓库索引增量),因为 fedora(7 天有效)和 openh264(14 天有效)的元数据仍在有效期内。紧接着再跑一次:

$ dnf makecache
Updating and loading repositories:
Repositories loaded.
Metadata cache created.
$ echo $?
0

全部命中缓存,直接进入 Repositories loaded。清空后重建可以看到全量下载:

$ dnf clean all
Removed 27 files, 17 directories (total of 263 MiB). 0 errors occurred.
$ dnf makecache
Updating and loading repositories:
 Fedora 44 - x86_64 - Updates           100% |   4.1 MiB/s |  12.0 MiB |  00m03s
 Fedora 44 openh264 (From Cisco) - x86_ 100% |   2.4 KiB/s |   5.3 KiB |  00m02s
 Fedora 44 - x86_64                     100% |   4.6 MiB/s |  36.4 MiB |  00m08s
Repositories loaded.
Metadata cache created.
$ du -sh /var/cache/libdnf5
105M	/var/cache/libdnf5

强制刷新(无视 metadata_expire):

$ dnf makecache --refresh
Updating and loading repositories:
 Fedora 44 - x86_64 - Updates           100% |   2.3 MiB/s |  11.8 MiB |  00m05s
 Fedora 44 openh264 (From Cisco) - x86_ 100% |   1.3 KiB/s |   5.3 KiB |  00m04s
 Fedora 44 - x86_64                     100% |   7.6 MiB/s |  36.5 MiB |  00m05s
Metadata cache created.
Repositories loaded.

解读:Fedora 44 全量元数据约 48 MiB(下载体积),解压落盘后缓存目录 105 MiB;makecache 默认按过期时间增量工作,--refresh 才无条件重下。系统自带的定时任务每天会自动跑一次等效操作,手工 makecache 主要用于:刚改完 repo 配置、刚挂载新源、或脚本里要保证元数据新鲜。

💡 缓存目录为什么叫 libdnf5:dnf4 时代缓存在 /var/cache/dnf/,dnf5 换到 /var/cache/libdnf5/,每个仓库一个 <repoid>-<哈希> 子目录。遇到"换个源就旧缓存作祟"的灵异问题时,rm -rf /var/cache/libdnf5(或 dnf clean all)后再 makecache 是标准复位手段。

3.2 clean:清除缓存

clean 按"缓存类型"删除数据,先看它支持哪些类型:

$ dnf clean --help
Usage:
  dnf5 [GLOBAL OPTIONS] clean [ARGUMENTS]

Arguments:
  cache_types                   List of cache types to clean up. Supported types: all, packages, metadata, dbcache, expire-cache

逐类实测(每步后查看缓存目录体积):

$ du -sh /var/cache/libdnf5
105M	/var/cache/libdnf5

$ dnf clean packages
Removed 0 files, 0 directories (total of 0 B). 0 errors occurred.
$ du -sh /var/cache/libdnf5
105M	/var/cache/libdnf5

$ dnf clean metadata
Removed 18 files, 6 directories (total of 104 MiB). 0 errors occurred.
$ du -sh /var/cache/libdnf5
16K	/var/cache/libdnf5

$ dnf clean dbcache
Removed 0 files, 0 directories (total of 0 B). 0 errors occurred.

$ dnf clean all
Removed 0 files, 0 directories (total of 0 B). 0 errors occurred.

解读:dnf5 的缓存主要是"元数据"(repo索引)与"下载的 rpm 包"两大块。上面 clean packages 清出 0 B,是因为此前的演示包已被清理;clean metadata 一把清掉 104 MiB。dnf clean packages 在 dnf5 里不会清掉 makecache 下载的元数据,clean metadata 也不会动已下载的 rpm,两者分开维护;一线运维最常用的还是 clean all。另一个差别:expire-cache 类型只是把元数据标记为过期(下次使用时重新下载),不是删除文件。

💡 dnf4 → dnf5 的 clean 差异:dnf4 支持 dbcache/keys/dbx/metadata/pkgs/all 等更多子类型;dnf5 精简为 all/packages/metadata/dbcache/expire-cache 五种。跨版本写通用脚本时,只依赖 clean all 最安全。

3.3 repolist / repo:查看仓库

repolist 是 repo list 的别名。默认只显示启用的仓库,且 dnf5 的输出只有两列:

$ dnf repolist
repo id               repo name
fedora                Fedora 44 - x86_64
fedora-cisco-openh264 Fedora 44 openh264 (From Cisco) - x86_64
updates               Fedora 44 - x86_64 - Updates

加 --all 看全部(含禁用仓库,多一列 status):

$ dnf repolist --all
repo id                         repo name                                           status
fedora                          Fedora 44 - x86_64                                 enabled
fedora-cisco-openh264           Fedora 44 openh264 (From Cisco) - x86_64           enabled
fedora-cisco-openh264-debuginfo Fedora 44 openh264 (From Cisco) - x86_64 - Debug  disabled
fedora-cisco-openh264-source    Fedora 44 openh264 (From Cisco) - x86_64 - Source disabled
fedora-debuginfo                Fedora 44 - x86_64 - Debug                        disabled
fedora-source                   Fedora 44 - Source                                disabled
updates                         Fedora 44 - x86_64 - Updates                       enabled
updates-debuginfo               Fedora 44 - x86_64 - Updates - Debug              disabled
updates-source                  Fedora 44 - Updates Source                        disabled
updates-testing                 Fedora 44 - x86_64 - Test Updates                 disabled
updates-testing-debuginfo       Fedora 44 - Test Updates Debug                    disabled
updates-testing-source          Fedora 44 - Test Updates Source                   disabled

单个仓库的详情用 repo info(repoinfo 是其别名,dnf repoinfo 无参可列全部启用仓库):

$ dnf repo info fedora
Updating and loading repositories:
Repositories loaded.
Repo ID              : fedora
Name                 : Fedora 44 - x86_64
Status               : enabled
Priority             : 99
Cost                 : 1000
Type                 : available
Metadata expire      : 604800 seconds (last: 2026-10-17 00:18:46)
Skip if unavailable  : false
Config file          : /etc/yum.repos.d/fedora.repo
URLs                 :
  Base URL           : https://mirrors.qlu.edu.cn/fedora/releases/44/Everything/x86_64/os/ (35 more)
  Metalink           : https://mirrors.fedoraproject.org/metalink?repo=fedora-44&arch=x86_64

解读三点:一是 Base URL 后的 35 more,说明 metalink 机制下 dnf 实际缓存了 36 个镜像候选,当前会话选中的这个是测速结果,你的机器上看到的第一条 URL 大概率不同,这是镜像调度而非配置错误;二是 Metadata expire: 604800 seconds 即 7 天,与 /etc/yum.repos.d/fedora.repo 里 metadata_expire=7d 一致;三是调试源与源码仓库(-debuginfo/-source)默认全部禁用,dnf config-manager enable 可按需打开(见 3.19)。

💡 metalink 与 baseurl:.repo 文件里 metalink= 指向镜像列表服务,dnf 启动时向它请求候选镜像并测速选优;baseurl= 则写死地址(Fedora 官方 repo 里被注释掉了)。内网机器推荐自建镜像后用 baseurl 直连,公网机器保持 metalink 即可。

3.4 search:按关键词搜包

search 在包名与 summary(一句话简介)里做关键词匹配:

$ dnf search cowsay
Updating and loading repositories:
Repositories loaded.
Matched fields: name (exact)
 cowsay.noarch	Configurable speaking/thinking cow
Matched fields: name, summary
 cowsay-beefymiracle.noarch	Cowsay file for the Beefy Miracle
Matched fields: name
 xcowsay.x86_64	Displays a cute cow and message on your desktop

多结果场景(截取前 15 行):

$ dnf search tree | sed -n '1,15p'
Updating and loading repositories:
Repositories loaded.
Matched fields: name (exact), summary
 tree.x86_64	File system tree viewer
Matched fields: name, summary
 NearTree-devel.i686	Development tools for compiling programs using NearTree
 NearTree-devel.x86_64	Development tools for compiling programs using NearTree
 cockpit-ostree.noarch	Cockpit user interface for rpm-ostree
 ebtree.i686	Elastic binary tree library
 ebtree.x86_64	Elastic binary tree library
 ebtree-devel.i686	Development files for ebtree
 ebtree-devel.x86_64	Development files for ebtree
 erlang-mqtree.x86_64	Index tree for MQTT topic filters
 fedora-release-ostree-desktop.noarch	Configuration package for rpm-ostree variants to add rpm-ostree polkit rules
 fedora-repos-ostree.noarch	OSTree specific files
 flexmark-java-tree-iteration.noarch	Flexmark library for recursive tree iteration
 geany-plugins-treebrowser.x86_64	Alternate file browser plugin providing a tree view of directories

搜不到时退出码是 0:

$ dnf search zzzznotexist
Updating and loading repositories:
Repositories loaded.
No matches found.
$ echo $?
0

解读:输出按 Matched fields 分组——name (exact) 精确同名排最前,其次 name, summary 双命中,再往后是仅 summary 命中。search 只查"名字+简介"两个字段,想按文件、依赖关系找包要用 provides/repoquery(见 3.7、3.8)。写脚本时注意:search 无结果返回 0,不能用 $? 判断命中与否,要 grep 输出内容。

3.5 info:查看包详情

$ dnf info cowsay
Updating and loading repositories:
Repositories loaded.
Available packages
Name           : cowsay
Epoch          : 0
Version        : 3.8.4
Release        : 5.fc44
Architecture   : noarch
Download size  : 54.5 KiB
Installed size : 80.5 KiB
Source         : cowsay-3.8.4-5.fc44.src.rpm
Repository     : fedora
Summary        : Configurable speaking/thinking cow
URL            : https://github.com/cowsay-org/cowsay
License        : GPL-2.0-or-later
Description    : cowsay is a configurable talking cow, written in Perl.  It operates
               : much as the figlet program does, and it is written in the same spirit
               : of silliness.
               : It generates ASCII pictures of a cow with a message. It can also generate
               : pictures of other animals.
Vendor         : Fedora Project

已安装的包会出现在 Installed packages 小节。查不存在的包退出码为 1:

$ dnf info nosuchpkg-404
Updating and loading repositories:
Repositories loaded.
No matching packages to list
$ echo $?
1

解读:Epoch: 0 表示无纪元;Repository: fedora 说明该版本来自发行版仓库而非 updates——cowsay 自 Fedora 44 首发后没有推送过更新。Available packages/Installed packages 的小节标题是区分安装状态的第一视觉线索;dnf info 同时给出 Download size 与 Installed size,估算磁盘占用比 list 方便。

💡 N-E-V-RA 命名法:RPM 包的完整标识是 Name-Epoch:Version-Release.Arch,如 cowsay-0:3.8.4-5.fc44.noarch。Version 是上游版本号(3.8.4),Release 是 Fedora 打包者的修订号(5.fc44,含目标发行版标记 .fc44)。读回显、写 repoquery 查询格式串、对比版本先后时都用得上这套记法。

3.6 list:按安装状态列包

list 按四种关系筛包,实测全部形态:

$ dnf list --installed | sed -n '1,12p'
Installed packages
alternatives.x86_64                      1.33-5.fc44                97840e1176ff4d8b98a420e1faba3487
audit-libs.x86_64                        4.2.1-1.fc44               0eae96ab45874228a86a12a132e699ed
authselect.x86_64                        1.7.1-1.fc44               97840e1176ff4d8b98a420e1faba3487
authselect-libs.x86_64                   1.7.1-1.fc44               97840e1176ff4d8b98a420e1faba3487
bash.x86_64                              5.3.9-3.fc44               97840e1176ff4d8b98a420e1faba3487
bzip2.x86_64                             1.0.8-23.fc44              97840e1176ff4d8b98a420e1faba3487
bzip2-libs.x86_64                        1.0.8-23.fc44              97840e1176ff4d8b98a420e1faba3487
ca-certificates.noarch                   2025.2.80_v9.0.304-7.fc44  0eae96ab45874228a86a12a132e699ed
coreutils.x86_64                         9.10-5.fc44                0eae96ab45874228a86a12a132e699ed
coreutils-common.x86_64                  9.10-5.fc44                0eae96ab45874228a86a12a132e699ed
cracklib.x86_64                          2.10.3-1.fc44              0eae96ab45874228a86a12a132e699ed

$ dnf list --installed | wc -l
147

$ dnf list --available cowsay
Updating and loading repositories:
Repositories loaded.
Available packages
cowsay.noarch 3.8.4-5.fc44 fedora

$ dnf list --upgrades | sed -n '1,12p'
Updating and loading repositories:
Repositories loaded.
Available upgrades
ca-certificates.noarch             2026.2.90_v9.0.317-1.fc44 updates
curl.x86_64                        8.18.0-14.fc44            updates
dnf5.x86_64                        5.4.6.0-1.fc44            updates
dnf5-plugins.x86_64                5.4.6.0-1.fc44            updates
elfutils-default-yama-scope.noarch 0.196-1.fc44              updates
elfutils-libelf.x86_64             0.196-1.fc44              updates
elfutils-libs.x86_64               0.196-1.fc44              updates
fedora-gpg-keys.noarch             44-2                      updates
fedora-repos.noarch                44-2                      updates
glib2.x86_64                       2.88.4-1.fc44             updates
glibc.x86_64                       2.43-9.fc44               updates

$ dnf list --obsoletes
Updating and loading repositories:
Repositories loaded.

最后两列的含义:--installed 行尾的长十六进制串是该包安装时来源仓库的 repodata 校验和(同批安装的包共享同一串,如 97840e1176ff4d8b98a420e1faba3487 是装机时刻的 fedora 仓库),--available/--upgrades 行尾是仓库名。--installed 共 147 行 = 1 行标题 + 146 个包,比 rpm -qa 少的正是 gpg-pubkey 密钥包——dnf list 不展示它。

--showduplicates 显示仓库里保留的多个历史版本:

$ dnf list --showduplicates cowsay
Updating and loading repositories:
Repositories loaded.
Available packages
cowsay.noarch 3.8.4-5.fc44 fedora

此处只列出一个版本,因为 Fedora 官方源只保留最新版;自建镜像若用 repomanage 保留多版本,这里就能看到全部(官方源的内核 installonly 包则天然多版本共存)。

⚠️ 一个从 dnf4 带来的书写陷阱,实测如下——不带 -- 时 installed 会被当成包名通配模式:

$ dnf list installed tree
Updating and loading repositories:
Repositories loaded.
Available packages
tree.x86_64 2.2.1-4.fc44 fedora

$ dnf list installed
Updating and loading repositories:
Repositories loaded.
No matching packages to list
$ echo $?
1

第二条命令报 No matching packages to list 退出码 1——它把 installed 当成了名为 installed 的包。所以要么全程 --installed,要么 dnf list installed 后必须跟包名。

3.7 provides:反查"谁提供这个文件/能力"

最常见用法:只知道命令路径,不知道属于哪个包。

$ dnf provides /usr/bin/cowsay
Updating and loading repositories:
 Fedora 44 - x86_64 - Updates           100% |   8.5 MiB/s |  26.8 MiB |  00m03s
 Fedora 44 openh264 (From Cisco) - x86_ 100% |   2.8 KiB/s |   7.3 KiB |  00m03s
 Fedora 44 - x86_64                     100% |  10.5 MiB/s |  56.6 MiB |  00m05s
Repositories loaded.
cowsay-3.8.4-5.fc44.noarch : Configurable speaking/thinking cow
Repo         : fedora
Matched From :
Filename     : /usr/bin/cowsay

也能按"能力名"(provide 字段)查:

$ dnf provides cowsay
Updating and loading repositories:
Repositories loaded.
cowsay-3.8.4-5.fc44.noarch : Configurable speaking/thinking cow
Repo         : fedora
Matched From :
Provide      : cowsay = 3.8.4-5.fc44

查不存在的提供项时,dnf5 会给出一行很实用的提示:

$ dnf provides 'perl(Cowsay)'
Updating and loading repositories:
Repositories loaded.
No matches found. If searching for a file, try specifying the full path or using a wildcard prefix ("*/") at the beginning.

解读:provides 匹配三个层面——文件路径、RPM Provide 能力(含 perl(Cowsay) 这类虚拟依赖)、以及包名本身。回显里 Matched From 之下区分 Filename 还是 Provide,一眼可见命中类型。这次查询还顺带触发了元数据重新下载(前 4 行进度条),因为文件清单(filelists)元数据默认不常驻,首次 provides 会按需拉取。

3.8 repoquery:结构化查询的瑞士军刀

repoquery 是 dnf5 查询体系里功能最全的命令,支持自定义输出格式和依赖方向查询。先看它支持的筛选维度(节选):

$ dnf repoquery --help | sed -n '1,40p'
Usage:
  dnf5 [GLOBAL OPTIONS] repoquery [OPTIONS] [ARGUMENTS]

Formatting:
  -i, --info                                   Show detailed information about the packages.
  --querytags                                  Display available tags for --queryformat.
  --queryformat=QUERYFORMAT                    Display format for packages. Default is "%{full_nevra}".
  --changelogs                                 Display package changelogs.
  --files                                      Like --queryformat="%{files}" but deduplicated and sorted.
  --sourcerpm                                  Like --queryformat="%{sourcerpm}" but deduplicated and sorted.
  --location                                   Like --queryformat="%{location}" but deduplicated and sorted.
  --conflicts                                  Like --queryformat="%{conflicts}" but deduplicated and sorted.
  --depends                                    Like --queryformat="%{depends}" but deduplicated and sorted.
  --enhances                                   Like --queryformat="%{enhances}" but deduplicated and sorted.
  --obsoletes                                  Like --queryformat="%{obsoletes}" but deduplicated and sorted.
  --provides                                   Like --queryformat="%{provides}" but deduplicated and sorted.
  --recommends                                 Like --queryformat="%{recommends}" but deduplicated and sorted.
  --requires                                   Like --queryformat="%{requires}" but deduplicated and sorted.
  --requires-pre                               Like --queryformat="%{requires_pre}" but deduplicated and sorted.
  --suggests                                   Like --queryformat="%{suggests}" but deduplicated and sorted.
  --supplements                                Like --queryformat="%{supplements}" but deduplicated and sorted.
  --qf=QUERYFORMAT                             Alias for '--queryformat'
  -l, --list                                   Alias for '--files'

Options:
  --available                                  Query available packages (default).
  --installed                                  Query installed packages.
  --installed-from-repo=REPO_ID,...            Filters installed packages by the ID of the repository they were installed from.
  --leaves                                     Limit to groups of installed packages not required by other installed packages.
  --userinstalled                              Limit to packages that are not installed as dependencies or weak dependencies.
  --duplicates                                 Limit to installed duplicate packages (i.e. more package versions for  the  same  name and architecture). Installonly packages are excluded from this set.
  --unneeded                                   Limit to unneeded installed packages (i.e. packages that were installed as dependencies but are no longer needed).
  --installonly                                Limit to installed installonly packages.
  --extras                                     Limit to installed packages that are not present in any available repository.
  --upgrades                                   Limit to available packages that provide an upgrade for some already installed package.
  --advisories=ADVISORY_NAME,...               Include content contained in advisories with specified name. List option.
  --advisory-severities=ADVISORY_SEVERITY,...  Include content contained in advisories with specified severity. List option. Can be "critical", "important", "moderate", "low", "none".
  --bzs=BUGZILLA_ID,...                        Include content contained in advisories that fix a Bugzilla ID, Eg. 123123. List option.
  --cves=CVE_ID,...                            Include content contained in advisories that fix a CVE (Common Vulnerabilities and Exposures) ID, Eg. CVE-2201-0123. List option.
  --security                                   Include content contained in security advisories.

基础查询与自定义格式:

$ dnf repoquery cowsay
Updating and loading repositories:
Repositories loaded.
cowsay-0:3.8.4-5.fc44.noarch

$ dnf repoquery --qf '%{name}-%{version}-%{release}.%{arch} (%{repoid})' cowsay
Updating and loading repositories:
Repositories loaded.
cowsay-3.8.4-5.fc44.noarch (fedora)

列文件清单与依赖(均截取部分):

$ dnf repoquery --list cowsay | sed -n '1,10p'
Updating and loading repositories:
Repositories loaded.
/etc/cowsay
/etc/cowsay/cowpath.d
/usr/bin/animalsay
/usr/bin/cowsay
/usr/bin/cowthink
/usr/share/bash-completion/completions/cowsay
/usr/share/cowsay
/usr/share/cowsay/cows
/usr/share/cowsay/cows/actually.cow
/usr/share/cowsay/cows/alpaca.cow

$ dnf repoquery --requires cowsay | sed -n '1,12p'
Updating and loading repositories:
Repositories loaded.
/usr/bin/perl
/usr/bin/sh
filesystem >= 3.6-1
perl(Cwd)
perl(File::Basename)
perl(File::Find)
perl(Getopt::Std)
perl(Text::Tabs)
perl(Text::Wrap)
perl-Encode

反向依赖:谁依赖 perl-interpreter(前 8 行):

$ dnf repoquery --whatrequires perl-interpreter | sed -n '1,8p'
Updating and loading repositories:
Repositories loaded.
389-ds-base-0:3.2.0-15.fc44.x86_64
389-ds-base-logconv-perl-0:3.2.3-5.fc44.x86_64
BackupPC-0:4.4.0-22.fc44.x86_64
EekBoek-0:2.051-15.fc44.noarch
GMT-common-0:6.6.0-5.fc44.noarch
IP2Location-0:8.7.0-3.fc44.i686
IP2Location-0:8.7.0-3.fc44.x86_64
LaTeXML-0:0.8.8-3.fc42.noarch

解读四点:默认查询对象是仓库里的可用包(--available 是默认值),查本机要显式 --installed;默认输出格式 %{full_nevra}(即 cowsay-0:3.8.4-5.fc44.noarch),--qf/--queryformat 可按 tag 自由拼装(全部可用 tag 用 dnf repoquery --querytags 查看);--whatrequires 只看硬依赖(requires),想含推荐依赖(recommends/supplements)需换 dnf repoquery --whatrecommends 等对应选项;输出按 NEVRA 全列,同一个包的 i686/x86_64 会各占一行,过滤时注意。

💡 provides vs repoquery 怎么选:日常"这文件哪来的"用 provides,一句话出结果;要做自动化处理(脚本消费、按格式拼接、依赖方向分析、安全通告过滤)一律 repoquery——它是 dnf5 里对 rpm 查询能力(rpm -q --qf 那套 tag 语法)在仓库维度的完整移植。

3.9 install:安装

先看 install 自身的选项(与依赖冲突处理相关,后面都会测):

$ dnf install --help
Usage:
  dnf5 [GLOBAL OPTIONS] install [OPTIONS] [ARGUMENTS]

Options:
  --allowerasing                               Allow removing of installed packages to resolve problems
  --skip-broken                                Allow resolving of depsolve problems by skipping packages
  --skip-unavailable                           Allow skipping unavailable packages
  --allow-downgrade                            Allow downgrade of dependencies for resolve of requested operation
  --no-allow-downgrade                         Disable downgrade of dependencies for resolve of requested operation
  --from-repo=REPO_ID,...                      The following items can be selected only from the specified repositories. All enabled repositories will still be used to satisfy dependencies.
  --from-vendor=VENDOR,...                     The following items can be selected only from the specified vendors. The vendor is ignored or vendor change policies (if allow_vendor_change=0) will still be used for items that satisfy dependencies.
  --downloadonly                               Only download packages for a transaction
  --offline                                    Store the transaction to be performed offline
  --advisories=ADVISORY_NAME,...               Include content contained in advisories with specified name. List option.
  --advisory-severities=ADVISORY_SEVERITY,...  Include content contained in advisories with specified severity. List option. Can be "critical", "important", "moderate", "low", "none".
  --bzs=BUGZILLA_ID,...                        Include content contained in advisories that fix a Bugzilla ID, Eg. 123123. List option.
  --cves=CVE_ID,...                            Include content contained in advisories that fix a CVE (Common Vulnerabilities and Exposures) ID, Eg. CVE-2201-0123. List option.
  --security                                   Include content contained in security advisories.
  --bugfix                                     Include content contained in bugfix advisories.
  --enhancement                                Include content contained in enhancement advisories.
  --newpackage                                 Include content contained in newpackage advisories.
  --store=STORED_TRANSACTION_PATH              Store the current transaction in a directory at the specified path instead of running it.
  --transient                                  Set up a transient overlay on /usr that will be discarded on reboot.
  --advisory=ADVISORY_NAME,...                 Alias for '--advisories'
  --bz=BUGZILLA_ID,...                         Alias for '--bzs'
  --cve=CVE_ID,...                             Alias for '--cves'

Arguments:
  specs                                        List of <package-spec-NPFB>|@<group-spec>|@<environment-spec> to install

单包安装(-y 自动确认):

$ dnf install -y tree
Updating and loading repositories:
Repositories loaded.
Package Arch   Version        Repository      Size
Installing:
 tree   x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Installing:         1 package

Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 120 KiB extra will be used (install 120 KiB, remove 0 B).
[1/1] tree-0:2.2.1-4.fc44.x86_64        100% | 142.7 KiB/s |  62.7 KiB |  00m00s
--------------------------------------------------------------------------------
[1/1] Total                             100% |  43.1 KiB/s |  62.7 KiB |  00m01s
Running transaction
[1/3] Verify package files              100% |   0.0   B/s |   1.0   B |  00m00s
[2/3] Prepare transaction               100% |  55.0   B/s |   1.0   B |  00m00s
[3/3] Installing tree-0:2.2.1-4.fc44.x8 100% |  89.7 KiB/s | 121.4 KiB |  00m01s
Complete!
$ echo $?
0

复核:

$ dnf list --installed tree
Installed packages
tree.x86_64 2.2.1-4.fc44 fedora
$ tree --version
tree v2.2.1 (c) 1996 - 2024 by Steve Baker, Thomas Moore, Francesc Rocher, Florian Sesser, Kyosuke Tokoro

连带依赖的全量事务(cowsay,依赖清单截取头尾):

$ dnf install -y cowsay
Updating and loading repositories:
Repositories loaded.
Package                 Arch   Version             Repository      Size
Installing:
 cowsay                 noarch 0:3.8.4-5.fc44      fedora      80.5 KiB
Installing dependencies:
 groff-base             x86_64 0:1.23.0-12.fc44    fedora       3.9 MiB
 ncurses                x86_64 0:6.6-1.fc44        fedora     611.4 KiB
 perl-AutoLoader        noarch 0:5.74-525.fc44     updates     20.6 KiB
 perl-B                 x86_64 0:1.89-525.fc44     updates    501.2 KiB
 perl-Carp              noarch 0:1.54-521.fc44     fedora      46.6 KiB
 perl-Class-Struct      noarch 0:0.68-525.fc44     updates     25.4 KiB
 perl-Data-Dumper       x86_64 0:2.192-523.fc44    updates    115.5 KiB
 ……(中间略)……
 perl-vars              noarch 0:1.05-525.fc44     updates      3.9 KiB
Installing weak dependencies:
 perl-NDBM_File         x86_64 0:1.18-525.fc44     updates     28.4 KiB

Transaction Summary:
 Installing:        64 packages

Total size of inbound packages is 8 MiB. Need to download 8 MiB.
After this operation, 28 MiB extra will be used (install 28 MiB, remove 0 B).
[ 1/64] perl-Text-Tabs+Wrap-0:2024.001- 100% | 179.8 KiB/s |  21.8 KiB |  00m00s
[ 2/64] cowsay-0:3.8.4-5.fc44.noarch    100% | 363.4 KiB/s |  54.5 KiB |  00m00s
 ……(中间略)……
[64/64] perl-NDBM_File-0:1.18-525.fc44. 100% | 606.3 KiB/s |  21.8 KiB |  00m00s
--------------------------------------------------------------------------------
[64/64] Total                           100% |   2.5 MiB/s |   8.5 MiB |  00m03s
Running transaction
[ 1/66] Verify package files            100% |   2.6 KiB/s |  64.0   B |  00m00s
[ 2/66] Prepare transaction             100% |   3.0 KiB/s |  64.0   B |  00m00s
[ 3/66] Installing ncurses-0:6.6-1.fc44 100% |  21.6 MiB/s | 618.0 KiB |  00m00s
 ……(中间略)……
[65/66] Installing cowsay-0:3.8.4-5.fc4 100% |   6.7 MiB/s |  89.6 KiB |  00m00s
[66/66] Installing perl-NDBM_File-0:1.1 100% | 117.5 KiB/s |  29.5 KiB |  00m00s
Complete!
$ echo 'dnf5 on Fedora 44' | cowsay
 ___________________
< dnf5 on Fedora 44 >
 -------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

解读:事务清单分三档——Installing(你点名的)、Installing dependencies(硬依赖,SAT 求解器补齐的)、Installing weak dependencies(弱依赖,默认装但可被 --setopt=install_weak_deps=False 关掉,实测见 3.20)。回显里 Installing: 64 packages 对应下载进度 64 项、rpm 层事务 66 步(多出的 2 步是 Verify package files 与 Prepare transaction),三个计数差值是正常结构,不是漏装。

💡 事务(transaction)是 dnf 的最小执行单位:不管你一条命令塞多少包,dnf 先把"要装的、要删的、要升的"整体求解成一个事务,预演给你看(Transaction Summary),确认后按依赖序一次性落库,中途任何一步失败整体回滚到事务前状态。这与 apt"逐个包顺序配置"的粒度不同,也是后面 history undo 能一键撤销整条命令的原因。

3.10 remove:卸载

先用 --assumeno 预演,不真删:

$ dnf remove --assumeno tree
Package Arch   Version        Repository      Size
Removing:
 tree   x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Removing:           1 package

After this operation, 120 KiB will be freed (install 0 B, remove 120 KiB).
Operation aborted by the user.
$ echo $?
1

确认无误后真实卸载:

$ dnf remove -y tree
Package Arch   Version        Repository      Size
Removing:
 tree   x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Removing:           1 package

After this operation, 120 KiB will be freed (install 0 B, remove 120 KiB).
Running transaction
[1/2] Prepare transaction               100% |  62.0   B/s |   1.0   B |  00m00s
[2/2] Removing tree-0:2.2.1-4.fc44.x86_ 100% | 281.0   B/s |   9.0   B |  00m00s
Complete!

$ dnf list --installed tree
No matching packages to list
$ echo $?
1

解读:--assumeno 让所有交互询问自动回答 no,事务在确认环节被 Operation aborted by the user. 拦下、退出码 1,是安全的"试跑"。remove 只删你点名的包;随它装进来的依赖是否一起清,由 clean_requirements_on_remove(本机默认 1)与显式 --no-autoremove 控制,见下节与 3.11。

💡 remove 的输出顺序是 stderr/stdout 交缠:仔细看 --assumeno 那段,After this operation, 120 KiB will be freed (install 0 B, remove 120 KiB). 出现在包表格之前,与 -y 版本相反——dnf5 把事务摘要写 stdout、进度与提示写 stderr,管道/重定向采集日志时顺序会错乱,需要原始顺序请 2>&1 合并后再看(排障实录见 FAQ)。

3.11 autoremove:清理孤儿依赖

autoremove 删除"当初作为依赖装上、现在已无人需要"的包。dnf4 时代删除包会顺手清依赖(clean_requirements_on_remove=1),但凡是你用 remove 时带过 --no-autoremove、或历史原因留下的孤儿,都得靠 autoremove 收尾。先用 cowsay 构造现场:上一节我们用 --no-autoremove 卸载 cowsay,把 61 个 Perl 依赖留在系统里:

$ dnf remove -y --no-autoremove cowsay
After this operation, 80 KiB will be freed (install 0 B, remove 80 KiB).
Running transaction
Package Arch   Version        Repository      Size
Removing:
 cowsay noarch 0:3.8.4-5.fc44 fedora      80.5 KiB

Transaction Summary:
 Removing:           1 package

[1/2] Prepare transaction               100% |  71.0   B/s |   1.0   B |  00m00s
[2/2] Removing cowsay-0:3.8.4-5.fc44.no 100% |   2.4 KiB/s |  63.0   B |  00m00s
Complete!

$ dnf list --installed | grep -c perl
61

预演 autoremove 能收回什么:

$ dnf autoremove --assumeno
Package                 Arch   Version             Repository      Size
Removing:
 groff-base             x86_64 0:1.23.0-12.fc44    fedora       3.9 MiB
 ncurses                x86_64 0:6.6-1.fc44        fedora     611.4 KiB
 perl-AutoLoader        noarch 0:5.74-525.fc44     updates     20.6 KiB
 perl-B                 x86_64 0:1.89-525.fc44     updates    501.2 KiB
 perl-Carp              noarch 0:1.54-521.fc44     fedora      46.6 KiB
 perl-Class-Struct      noarch 0:0.68-525.fc44     updates     25.4 KiB
 perl-Data-Dumper       x86_64 0:2.192-523.fc44    updates    115.5 KiB
 perl-Digest            noarch 0:1.20-521.fc44     fedora      35.3 KiB
 perl-Digest-MD5        x86_64 0:2.59-521.fc44     fedora      59.6 KiB
 perl-DynaLoader        x86_64 0:1.57-525.fc44     updates     32.1 KiB
 perl-Encode            x86_64 4:3.21-521.fc44     fedora       4.7 MiB
 perl-Errno             noarch 0:1.38-525.fc44     updates      8.4 KiB
 ……(中间略)……
 Removing:          63 packages

After this operation, 28 MiB will be freed (install 0 B, remove 28 MiB).
Operation aborted by the user.
$ echo $?
1

真实清理:

$ dnf autoremove -y
 ……(中间略)……
[63/64] Removing ncurses-0:6.6-1.fc44.x 100% |   1.6 KiB/s |  46.0   B |  00m00s
[64/64] Removing groff-base-0:1.23.0-12 100% |   4.9 KiB/s | 231.0   B |  00m00s
Complete!
$ echo $?
0
$ dnf list --installed | grep -c perl
0

解读:63 个孤儿包、28 MiB,一条 autoremove 全部收回。--no-autoremove(remove 的选项)与 autoremove(独立子命令)是同一枚硬币的两面:前者"删主包留依赖",后者"专收依赖"。生产机器上 autoremove 前务必先 --assumeno 过目清单——孤儿判定依赖"安装原因"标记,人工 rpm -ivh 装的包会被视为用户安装、不会被误删,但被 mark 改过原因的包会改变结局(mark 实测见 3.20)。

3.12 upgrade:升级

upgrade 升级指定包或全系统;update 是它的别名。全量升级预演(截取头尾):

$ dnf upgrade --assumeno
Updating and loading repositories:
Repositories loaded.
Package                                  Arch   Version                     Repository                            Size
Upgrading:
 ca-certificates                         noarch 0:2026.2.90_v9.0.317-1.fc44 updates                            2.7 MiB
   replacing ca-certificates             noarch 0:2025.2.80_v9.0.304-7.fc44 0eae96ab45874228a86a12a132e699ed   2.7 MiB
 curl                                    x86_64 0:8.18.0-14.fc44            updates                          480.0 KiB
   replacing curl                        x86_64 0:8.18.0-8.fc44             0eae96ab45874228a86a12a132e699ed 480.0 KiB
 dnf5                                    x86_64 0:5.4.6.0-1.fc44            updates                            3.4 MiB
   replacing dnf5                        x86_64 0:5.4.3.0-2.fc44            0eae96ab45874228a86a12a132e699ed   3.3 MiB
 dnf5-plugins                            x86_64 0:5.4.6.0-1.fc44            updates                            1.6 MiB
   replacing dnf5-plugins                x86_64 0:5.4.3.0-2.fc44            0eae96ab45874228a86a12a132e699ed   1.6 MiB
 ……(中间略)……
Total size of inbound packages is 21 MiB. Need to download 21 MiB.
After this operation, 1 MiB extra will be used (install 67 MiB, remove 65 MiB).
Operation aborted by the user.
$ echo $?
1

单包升级(已是最新时):

$ rpm -q tar
tar-1.35-9.fc44.x86_64
$ dnf upgrade -y tar
Updating and loading repositories:
Repositories loaded.
Nothing to do.
$ rpm -q tar
tar-1.35-9.fc44.x86_64

解读:Upgrading 区块里每个新版本下面缩进行是"replacing 被替换的旧版",旧版行尾的长哈希再次表明旧包来自装机时刻的仓库。Nothing to do. 不算错误(退出码 0)。跨大版本升级不用 upgrade,用 dnf system-upgrade 子命令(本文不展开,注意 --releasever 配合它才是正确姿势,单包场景见 3.15)。

3.13 check-update:只查不升,脚本专用

check-update(本名 check-upgrade)列出可升级项但不做任何改动,专为巡检脚本设计。它的退出码有特殊约定,实测(当时确有可用更新):

$ dnf check-update
Updating and loading repositories:
Repositories loaded.
Upgrades
ca-certificates.noarch             2026.2.90_v9.0.317-1.fc44 updates
curl.x86_64                        8.18.0-14.fc44            updates
dnf5.x86_64                        5.4.6.0-1.fc44            updates
dnf5-plugins.x86_64                5.4.6.0-1.fc44            updates
elfutils-default-yama-scope.noarch 0.196-1.fc44              updates
elfutils-libelf.x86_64             0.196-1.fc44              updates
elfutils-libs.x86_64               0.196-1.fc44              updates
fedora-gpg-keys.noarch             44-2                      updates
fedora-repos.noarch                44-2                      updates
glib2.x86_64                       2.88.4-1.fc44             updates
glibc.x86_64                       2.43-9.fc44               updates
glibc-common.x86_64                2.43-9.fc44               updates
glibc-minimal-langpack.x86_64      2.43-9.fc44               updates
libcap-ng.x86_64                   0.9.6-1.fc44              updates
libcurl.x86_64                     8.18.0-14.fc44            updates
$ echo $?
100

解读:退出码 100 = 有可用更新,0 = 全部最新,1 = 出错。这是 yum 时代沿用至今的约定,巡检脚本据此分支:if dnf check-update -q >/dev/null; then echo 最新; else echo 有更新待装; fi(100 走 else 分支)。输出格式与 dnf list --upgrades 相同,想要更结构化的数据可改用 dnf repoquery --upgrades。

顺带验证两个易错点:dnf help 子命令不存在;参数缺失是退出码 2:

$ dnf help upgrade
Unknown argument "help" for command "dnf5". Add "--help" for more information about the arguments.
It could be a command provided by a plugin, try: dnf5 install 'dnf5-command(help)'
$ echo $?
2

$ dnf install
Missing positional argument "specs" for command "install". Add "--help" for more information about the arguments.
$ echo $?
2

$ dnf
Missing command. Add "--help" for more information about the arguments.
$ echo $?
2

3.14 reinstall:重装

文件损坏、误删配置后的标准修复手段——同版本号重新落一遍盘:

$ dnf reinstall -y tree
Updating and loading repositories:
Repositories loaded.
Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 0 B extra will be used (install 120 KiB, remove 120 KiB).
Package           Arch   Version        Repository      Size
Reinstalling:
 tree             x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB
   replacing tree x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Reinstalling:       1 package
 Replacing:          1 package

[1/1] tree-0:2.2.1-4.fc44.x86_64        100% | 139.5 KiB/s |  62.7 KiB |  00m00s
--------------------------------------------------------------------------------
[1/1] Total                             100% |  37.1 KiB/s |  62.7 KiB |  00m02s
Running transaction
[1/4] Verify package files              100% |   0.0   B/s |   1.0   B |  00m00s
[2/4] Prepare transaction               100% | 222.0   B/s |   2.0   B |  00m00s
[3/4] Reinstalling tree-0:2.2.1-4.fc44. 100% |   6.2 MiB/s | 121.4 KiB |  00m00s
[4/4] Removing tree-0:2.2.1-4.fc44.x86_ 100% | 375.0   B/s |   9.0   B |  00m00s
Complete!
$ rpm -q tree
tree-2.2.1-4.fc44.x86_64

对未安装的包与不存在的包都会拒绝(实测退出码均 1):

$ dnf reinstall --assumeno cowsay
Updating and loading repositories:
Repositories loaded.
Failed to resolve the transaction:
Packages for argument 'cowsay' available, but not installed.

$ dnf reinstall --assumeno nosuchpkg-404
Updating and loading repositories:
Repositories loaded.
Failed to resolve the transaction:
No match for argument: nosuchpkg-404
You can try to add to command line:
  --skip-unavailable to skip unavailable packages

解读:回显里 After this operation, 0 B extra will be used (install 120 KiB, remove 120 KiB) 精确表达了"重装不占新空间"。注意 dnf5 的报错文案区分了两种失败:available, but not installed(包存在但你没装过, reinstall 无从谈起)与 No match for argument(仓库里根本没有)。后者会贴心提示 --skip-unavailable,但那会静默跳过目标包,脚本里慎用(实测见 3.20)。

3.15 downgrade:降级(含 --releasever 实测)

降级是排障刚需(新版有问题回退旧版)。难点在于:官方源通常只保留最新版本,同源没有更低版本时 downgrade 会拒绝执行。实测两种情形。

情形一:同仓库内没有更低版本:

$ rpm -q tree
tree-2.2.1-4.fc44.x86_64
$ dnf downgrade --assumeno tree
Updating and loading repositories:
Repositories loaded.
Failed to resolve the transaction:
The lowest available version of the "tree.x86_64" package is already installed, cannot downgrade it.
Nothing to do.
$ echo $?
0

情形二:用 --releasever=43 把仓库指向上一版 Fedora 43(其源里存有 tree 2.2.1-2.fc43),先预演:

$ dnf --releasever=43 downgrade --assumeno tree
……(略,预演事务与真跑输出一致,见下)……

真实降级:

$ dnf --releasever=43 -y downgrade tree
Updating and loading repositories:
 Fedora 43 - x86_64                     100% |   5.6 MiB/s |  36.6 MiB |  00m06s
 Fedora 43 openh264 (From Cisco) - x86_ 100% |   1.9 KiB/s |   5.3 KiB |  00m02s
Repositories loaded.
Package Arch   Version        Repository      Size
Downgrading:
 tree   x86_64 0:2.2.1-2.fc43 fedora     120.0 KiB
   replacing tree x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Downgrading:        1 package

Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 0 B extra will be used (install 120 KiB, remove 120 KiB).
[1/1] tree-0:2.2.1-2.fc43.x86_64        100% | 406.8 KiB/s |  62.7 KiB |  00m00s
--------------------------------------------------------------------------------
[1/1] Total                             100% | 110.7 KiB/s |  62.7 KiB |  00m01s
Running transaction
[1/4] Verify package files              100% |   0.0   B/s |   1.0   B |  00m00s
[2/4] Prepare transaction               100% | 125.0   B/s |   1.0   B |  00m00s
[3/4] Downgrading tree-0:2.2.1-2.fc43.x 100% |   1.9 MiB/s | 120.0 KiB |  00m00s
[4/4] Removing tree-0:2.2.1-4.fc44.x86_ 100% | 375.0   B/s |   9.0   B |  00m00s
Complete!
$ rpm -q tree
tree-2.2.1-2.fc43.x86_64

升回最新版收尾:

$ dnf upgrade -y tree
Updating and loading repositories:
Repositories loaded.
Package Arch   Version        Repository      Size
Upgrading:
 tree   x86_64 0:2.2.1-4.fc44 updates   120.0 KiB
   replacing tree x86_64 0:2.2.1-2.fc43 fedora 120.0 KiB
 ……(中间略)……
Complete!
$ rpm -q tree
tree-2.2.1-4.fc44.x86_64

解读:Downgrading 区块结构与 upgrade 的镜像对称;--releasever 只影响元数据 URL 里的发行版变量(repo 文件里的 $releasever),不改变本机 rpmdb——所以严格说这是"从 F43 源装旧包",不是系统回退。它适合单包应急回退;整系统跨版本回退没有官方支持路径(Fedora 只支持向前 system-upgrade)。

⚠️ 注意情形一的退出码是 0 而非报错退出:cannot downgrade it + Nothing to do. 被视为"无事可做"而非失败,脚本判断降级是否发生要靠 rpm -q 比对版本,不能只看 $?。

💡 --releasever 与 installroot 的组合:dnf 支持给另一个根目录装系统(--installroot=/mnt/sysimage --releasever=44),救援盘修复系统、构建镜像时用。本文 3.19 的 config-manager 实测也顺带验证了 --releasever 对 URL 变量的替换效果(回显里仓库名直接变成 Fedora 43)。

3.16 download 与 --downloadonly:把包拿回来

download 把 rpm 落到当前目录(不进 rpmdb),是离线分发、内网补丁包制作的基础命令:

$ dnf download cowsay
Updating and loading repositories:
Repositories loaded.
Downloading Packages:
 cowsay-0:3.8.4-5.fc44.noarch           100% | 368.3 KiB/s |  54.5 KiB |  00m00s
$ ls -l
total 60
-rw-r--r-- 1 root root 55823 Oct 17 00:17 cowsay-3.8.4-5.fc44.noarch.rpm

--url 只打印下载地址不落盘(注意地址是镜像调度的结果):

$ dnf download --url cowsay
Updating and loading repositories:
Repositories loaded.
https://mirror.nyist.edu.cn/fedora/releases/44/Everything/x86_64/os/Packages/c/cowsay-3.8.4-5.fc44.noarch.rpm
$ ls | wc -l
1

--resolve 连依赖一起解析下载(64 个 rpm 全部落到当前目录,这里列前几个):

$ dnf download --resolve cowsay
$ ls *.rpm | wc -l
64
$ ls -l | sed -n '1,7p'
total 9072
-rw-r--r-- 1 root root   55823 Oct 17 00:17 cowsay-3.8.4-5.fc44.noarch.rpm
-rw-r--r-- 1 root root 1177840 Oct 17 00:17 groff-base-1.23.0-12.fc44.x86_64.rpm
-rw-r--r-- 1 root root  440103 Oct 17 00:17 ncurses-6.6-1.fc44.x86_64.rpm
-rw-r--r-- 1 root root   21040 Oct 17 00:17 perl-AutoLoader-5.74-525.fc44.noarch.rpm
-rw-r--r-- 1 root root  181378 Oct 17 00:17 perl-B-1.89-525.fc44.x86_64.rpm
-rw-r--r-- 1 root root   29473 Oct 17 00:17 perl-Carp-1.54-521.fc44.noarch.rpm

另一条路:install --downloadonly 只下载进包缓存,不安装:

$ dnf install --downloadonly -y tree
Updating and loading repositories:
Repositories loaded.
Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 120 KiB extra will be used (install 120 KiB, remove 0 B).
The operation will only download packages for the transaction.
Package Arch   Version        Repository      Size
Installing:
 tree   x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Installing:         1 package

[1/1] tree-0:2.2.1-4.fc44.x86_64        100% | 406.8 KiB/s |  62.7 KiB |  00m00s
--------------------------------------------------------------------------------
[1/1] Total                             100% | 110.7 KiB/s |  62.7 KiB |  00m01s
Complete!
$ dnf list --installed tree
No matching packages to list
$ find /var/cache/libdnf5 -name '*.rpm'
/var/cache/libdnf5/fedora-cff72538bc9825a4/packages/tree-2.2.1-4.fc44.x86_64.rpm

解读与差异表:

维度dnf download [--resolve]dnf install --downloadonly
落盘位置当前目录(或 --destdir)/var/cache/libdnf5/<repo>/packages/
依赖解析可选(加 --resolve)总是解析完整事务
后续用法拷走离线装(dnf install *.rpm/rpm -Uvh)直接 dnf install 时命中缓存免下载
--url 支持支持(只打印地址)不支持

--resolve 默认跳过已安装的依赖,要强制全量下载加 --alldeps;--url 配合 --allmirrors 可打印所有镜像候选,配合 --urlprotocol=https 可过滤协议。本文实测下载地址落在 mirror.nyist.edu.cn,而 3.3 的 repo info 显示候选列表首位是 mirrors.qlu.edu.cn——不同命令、不同时刻选中的镜像可能不同,都是 metalink 正常调度。

3.17 group 与 environment:软件组管理

软件组(comps group)是仓库元数据里预定义的包集合,装一组应用不用逐个点名。查看组与组内容:

$ dnf group list | sed -n '1,22p'
Updating and loading repositories:
Repositories loaded.
ID                          Name                                        Installed
neuron-modelling-simulators Neuron Modelling Simulators                        no
kde-education               KDE Educational applications                       no
kde-media                   KDE Multimedia support                             no
kde-mobile                  KDE Mobile                                         no
kde-mobile-apps             KDE Mobile Apps                                    no
kde-office                  KDE Office                                         no
kde-pim                     KDE PIM                                            no
kde-software-development    KDE Software Development                           no
kf6-software-development    KDE Frameworks 6 Software Development              no
libreoffice                 LibreOffice                                        no
mate-applications           MATE Applications                                  no
milkymist                   Milkymist                                          no
network-server              Network Servers                                    no
kde-desktop                 KDE                                                no
office                      Office/Productivity                                no
python-classroom            Python Classroom                                   no
python-science              Python Science                                     no
robotics-suite              Robotics                                           no
rpm-development-tools       RPM Development Tools                              no
security-lab                Security Lab                                       no
sound-and-video             Sound and Video                                    no

$ dnf group list | wc -l
53

环境组(比组更高一级的"套装",如整个桌面环境):

$ dnf environment list | sed -n '1,10p'
Updating and loading repositories:
Repositories loaded.
ID                                Name                                 Installed
custom-environment                Fedora Custom Operating System              no
workstation-product-environment   Fedora Workstation                          no
server-product-environment        Fedora Server Edition                       no
cloud-server-environment          Fedora Cloud Server                         no
kde-desktop-environment           KDE Plasma Workspaces                       no
kde-mobile-environment            KDE Plasma Mobile                           no
xfce-desktop-environment          Xfce Desktop                                no
phosh-desktop-environment         Phosh Desktop                               no
lxde-desktop-environment          LXDE Desktop                                no

组详情(text-internet 组,只含可选包):

$ dnf group info text-internet
Updating and loading repositories:
Repositories loaded.
Id                   : text-internet
Name                 : Text-based Internet
Description          : This group includes text-based email, web, and chat clients. These applications do not require the X Window System.
Installed            : yes
Order                :
Langonly             :
Uservisible          : yes
Repositories         : @System
Optional packages    : abook
                     : alpine
                     : argus
                     : aria2
                     : axel
                     : cadaver
                     : centerim
                     : elinks
                     : epic
                     : fetchmail
                     : fpaste
                     : iperf
                     : irssi
                     : isync
                     : lftp
                     : lynx
                     : mailprocessing
                     : mutt
                     : ncftp
                     : nmh
                     : offlineimap
                     : rss2email
                     : rtorrent
                     : slrn
                     : snownews
                     : tftp
                     : tin
                     : w3m
                     : websec
                     : whatmask
                     : wondershaper
                     : youtube-dl

组的安装是幂等的——已安装再装一次只做确认:

$ dnf group install -y text-internet
Updating and loading repositories:
Repositories loaded.
Group "text-internet" is already installed.

Nothing to do.

$ dnf group list --installed
Updating and loading repositories:
Repositories loaded.
ID                   Name                Installed
text-internet        Text-based Internet       yes

$ dnf group remove -y text-internet
Updating and loading repositories:
Repositories loaded.
Package              Arch   Version Repository      Size
Removing groups:
 Text-based Internet

Transaction Summary:

After this operation, 0 B extra will be used (install 0 B, remove 0 B).
Running transaction
Complete!

text-internet 只含 Optional 包(组安装不装可选包),所以装与删都只是"组标记"的进出,0 字节变化。下面换 fonts 组演示真实的组安装——它默认列表里看不到(grep -cw fonts 为 0),是个隐藏组:

$ dnf group list | grep -cw fonts
0

$ dnf group list --hidden | grep -w fonts
legacy-fonts                Legacy Fonts                                       no
fonts                       Fonts                                              no

$ dnf group info fonts | sed -n '1,26p'
Updating and loading repositories:
Repositories loaded.
Id                   : fonts
Name                 : Fonts
Description          : Fonts packages for rendering text on the desktop.
Installed            : no
Order                :
Langonly             :
Uservisible          : no
Repositories         : fedora, updates
Default packages     : default-fonts-cjk-mono
                     : default-fonts-cjk-sans
                     : default-fonts-cjk-serif
                     : default-fonts-core-emoji
                     : default-fonts-core-math
                     : default-fonts-core-mono
                     : default-fonts-core-sans
                     : default-fonts-core-serif
                     : default-fonts-other-mono
                     : default-fonts-other-sans
                     : default-fonts-other-serif

$ dnf group install -y fonts
Package                                        Arch   Version               Repository      Size
Installing group/module packages:
 default-fonts-cjk-mono                        noarch 0:4.3-1.fc44          fedora     424.0   B
 default-fonts-cjk-sans                        noarch 0:4.3-1.fc44          fedora       2.2 KiB
 default-fonts-cjk-serif                       noarch 0:4.3-1.fc44          fedora     417.0   B
 default-fonts-core-emoji                      noarch 0:4.3-1.fc44          fedora     338.0   B
 default-fonts-core-math                       noarch 0:4.3-1.fc44          fedora     334.0   B
 default-fonts-core-mono                       noarch 0:4.3-1.fc44          fedora     371.0   B
 ……(中间略)……
[137/137] Installing default-fonts-core 100% | 113.0 KiB/s |  18.2 KiB |  00m00s
Complete!
$ rpm -qa | grep -c font
135

安装后验证一个反直觉现象——隐藏组即使装上了也不出现在 group list --installed 里:

$ dnf group list --installed
Updating and loading repositories:
Repositories loaded.

卸载收尾:

$ dnf group remove -y fonts
 ……(中间略)……
[135/136] Removing fonts-filesystem-1:5 100% |   4.9 KiB/s |   5.0   B |  00m00s
[136/136] Removing google-noto-fonts-co 100% | 235.0   B/s |   4.0   B |  00m00s
Complete!
$ rpm -qa | grep -c font
0

解读:组元数据把包分四档——Mandatory(必装,缺失会警告)、Default(默认装)、Optional(默认不装)、Extra(特殊规则);fonts 组全部是 Default 档,所以一次装入 137 个包。判断"某组会装多少东西"先 group info 看分档,别拿组名猜。隐藏组(Uservisible: no)是给依赖关系用的"内部组",确认其状态要么 group list --hidden,要么 group info 看 Installed 字段。

💡 group 与 environment 的层级:environment(环境组)= 若干 group 的集合 + 若干默认组开关,如 server-product-environment(Fedora Server Edition)就是一组服务类 group 的打包。装机用 dnf install @server-product-environment 或安装器选环境;运维中 environment 不常动,group 才是日常单位。@组名 这种前缀写法与 dnf group install 组名 等价(install 的 specs 参数格式 <package-spec>|@<group-spec>|@<environment-spec>,见 3.9 的 --help)。

3.18 history:事务历史与 undo/rollback

dnf5 把每次事务记入历史库(含命令行、时间、影响的包),并支持反向执行。先看子命令面:

$ dnf history --help
Usage:
  dnf5 [GLOBAL OPTIONS] history <COMMAND> ...

Query Commands:
  list                          List transactions
  info                          Print details about transactions

Software Management Commands:
  undo                          Revert all actions from the specified transaction
  redo                          Repeat all actions from the specified transaction
  rollback                      Undo all transactions performed after the specified transaction
  store                         [experimental] Store transaction to a file

记录当前基线事务号,然后连续安装两个包制造现场:

$ dnf history list | sed -n '1,3p'
ID Command line                           Date and time       Action(s) Altered
30 dnf group remove -y fonts              2026-10-17 00:18:17               136
29 dnf group install -y fonts             2026-10-17 00:18:16               136

$ dnf install -y figlet | tail -3
Running transaction
[3/3] Installing figlet-0:2.2.5-39.fc44 100% |  15.4 MiB/s | 679.5 KiB |  00m00s
Complete!

$ dnf install -y sl | tail -3
Running transaction
[3/3] Installing sl-0:5.02-25.fc44.x86_ 100% | 783.9 KiB/s |  22.7 KiB |  00m00s
Complete!

$ dnf history list | sed -n '1,8p'
ID Command line                          Date and time       Action(s) Altered
32 dnf install -y sl                     2026-10-17 00:18:28                 1
31 dnf install -y figlet                 2026-10-17 00:18:27                 1
30 dnf group remove -y fonts             2026-10-17 00:18:17               136
29 dnf group install -y fonts            2026-10-17 00:18:16               136
28 dnf group remove -y text-internet     2026-10-17 00:18:05                 1
27 dnf remove -y tree                    2026-10-17 00:17:35                 1
26 dnf upgrade -y tree                   2026-10-17 00:17:34                 2

事务详情(含前后 rpmdb 哈希):

$ dnf history info 32
Transaction ID : 32
Begin time     : 2026-10-17 00:18:28
Begin rpmdb    : 47a4aa1ddddaf5e4b58e8a676caef5d5571cd2a196dacd6831fc0ccecc47d136
End time       : 2026-10-17 00:18:28
End rpmdb      : 7502f001b18332f8aa322d089e8162116fbafb596d3bfe2d01a65cfe40fe3e33
User           : 0 Super User <root>
Status         : Ok
Releasever     : 44
Description    : dnf install -y sl
Comment        :
Packages altered:
  Action  Package                  Reason Repository
  Install sl-0:5.02-25.fc44.x86_64 User   fedora

undo 撤销单个事务(只回退 sl,figlet 保留):

$ dnf -y history undo 32
Updating and loading repositories:
Repositories loaded.
Package Arch   Version        Repository      Size
Removing:
 sl     x86_64 0:5.02-25.fc44 fedora      21.2 KiB

Transaction Summary:
 Removing:           1 package

After this operation, 21 KiB will be freed (install 0 B, remove 21 KiB).
Running transaction
[1/2] Prepare transaction               100% | 100.0   B/s |   1.0   B |  00m00s
[2/2] Removing sl-0:5.02-25.fc44.x86_64 100% | 400.0   B/s |  10.0   B |  00m00s
Complete!
$ rpm -q sl
package sl is not installed
$ rpm -q figlet
figlet-2.2.5-39.fc44.x86_64

rollback 回滚到基线事务 30(撤销 30 之后发生的一切,即把 figlet 也撤掉):

$ dnf -y history rollback 30
After this operation, 669 KiB will be freed (install 0 B, remove 669 KiB).
Running transaction
[1/2] Prepare transaction               100% | 100.0   B/s |   1.0   B |  00m00s
[2/2] Removing figlet-0:2.2.5-39.fc44.x 100% |   2.9 KiB/s |  77.0   B |  00m00s
Complete!
$ rpm -q figlet
package figlet is not installed

undo/rollback 本身也各留痕一条,last 关键字与区间写法都可用:

$ dnf history list | sed -n '1,7p'
ID Command line                            Date and time       Action(s) Altered
34 dnf -y history rollback 30              2026-10-17 00:18:29                 1
33 dnf -y history undo 32                  2026-10-17 00:18:29                 1
32 dnf install -y sl                       2026-10-17 00:18:28                 1
31 dnf install -y figlet                   2026-10-17 00:18:27                 1
30 dnf group remove -y fonts               2026-10-17 00:18:17               136
29 dnf group install -y fonts              2026-10-17 00:18:16               136

$ dnf history info last | sed -n '1,8p'
Transaction ID : 34
Begin time     : 2026-10-17 00:18:29
Begin rpmdb    : 47a4aa1ddddaf5e4b58e8a676caef5d5571cd2a196dacd6831fc0ccecc47d136
End time       : 2026-10-17 00:18:29
End rpmdb      : 9fa9d614474001e7d901c2ec30ce166418457acbf93e5e97eb12e22bbb9de609
User           : 0 Super User <root>
Status         : Ok

$ dnf history info 30..31 | sed -n '1,6p'
Transaction ID : 31
Begin time     : 2026-10-17 00:18:27
Begin rpmdb    : 9fa9d614474001e7d901c2ec30ce166418457acbf93e5e97eb12e22bbb9de609
End time       : 2026-10-17 00:18:27
End rpmdb      : 47a4aa1ddddaf5e4b58e8a676caef5d5571cd2a196dacd6831fc0ccecc47d136

解读:undo 32 = 反向执行 32 号事务;rollback 30 = 反向执行 30 号之后的所有事务,两者都生成新事务留痕(33、34 号),历史只增不改。Status: Ok 之外还可能出现 Undo 等状态标记;Begin rpmdb/End rpmdb 的哈希可用来核对两次事务之间 rpmdb 是否被第三方(如手工 rpm 命令)动过——审计时非常值钱。store/replay 是 dnf5 新增的实验特性:把事务存成目录,拿到另一台机器重放,适合批量装机场景,生产使用前先在测试机验证。

💡 undo 的边界:undo 反向求解"把当时的包集合变回去",如果该事务涉及包在当前仓库已下架,undo 可能求解失败——历史回滚不是时光机,它依赖当下可用的仓库。核心库升级这类不可逆事务,undo 前务必先 history info 看清单再动手。

3.19 config-manager:仓库启用/禁用与新增(dnf5 新语法)

dnf5 的 config-manager 从 dnf4 的"一长串短横线选项"改成了子命令结构:

$ dnf config-manager --help
Usage:
  dnf5 [GLOBAL OPTIONS] config-manager <COMMAND> ...

Description:
  Manage main and repositories configuration, variables and add new repositories.

Commands:
  addrepo                       Add repositories from the specified configuration file or define a new repository using user options
  setopt                        Set configuration and repositories options
  unsetopt                      Unset/remove configuration and repositories options
  setvar                        Set variables
  unsetvar                      Unset/remove variables
  enable                        Enables repositories
  disable                       Disables repositories

旧语法已死——dnf4 的 --set-enabled 在 dnf5 直接报错:

$ dnf config-manager --set-enabled fedora-source
Unknown argument "--set-enabled" for command "config-manager". Add "--help" for more information about the arguments.
$ echo $?
2

新语法启用 fedora-source 源:

$ dnf config-manager enable fedora-source
$ dnf repolist
repo id               repo name
fedora                Fedora 44 - x86_64
fedora-cisco-openh264 Fedora 44 openh264 (From Cisco) - x86_64
fedora-source         Fedora 44 - Source
updates               Fedora 44 - x86_64 - Updates

再看持久化写到了哪里——这是 dnf5 与 dnf4 的关键行为差异(--set-enabled 在 dnf4 里是改 /etc/yum.repos.d/*.repo,dnf5 是写覆盖层)。enable 之后覆盖层文件内容:

$ cat /etc/dnf/repos.override.d/99-config_manager.repo
# Generated by libdnf5.
# Do not modify this file manually, use dnf5 config-manager instead.
[fedora-source]
enabled=1

disable 之后再看同一文件(.repo 原文件自始至终未被改动):

$ dnf config-manager disable fedora-source
$ cat /etc/dnf/repos.override.d/99-config_manager.repo
# Generated by libdnf5.
# Do not modify this file manually, use dnf5 config-manager instead.
[fedora-source]
enabled=0

恢复默认后 repolist 复核:

$ dnf repolist
repo id               repo name
fedora                Fedora 44 - x86_64
fedora-cisco-openh264 Fedora 44 openh264 (From Cisco) - x86_64
updates               Fedora 44 - x86_64 - Updates

setopt 改仓库级选项,实测 updates.metadata_expire=4h:

$ dnf config-manager setopt updates.metadata_expire=4h
$ echo $?
0
$ grep -rn 'metadata_expire' /etc/dnf/repos.override.d/ 2>/dev/null
/etc/dnf/repos.override.d/99-config_manager.repo:6:metadata_expire=4h
$ dnf --dump-repo-config=updates | grep metadata_expire
metadata_expire = 14400
$ dnf config-manager unsetopt updates.metadata_expire
$ dnf --dump-repo-config=updates | grep metadata_expire
metadata_expire = 21600

但 main 主配置不支持 setopt(与 dnf4 不同,实测报错):

$ dnf config-manager setopt main.keepcache=True
ConfigManagerError: Cannot set repository option "main.keepcache=True": Option "keepcache" not found
$ echo $?
1

变量管理 setvar/unsetvar(格式为 变量名=值 单参数):

$ dnf config-manager setvar my_test_var=hello44
$ cat /etc/dnf/vars/my_test_var
hello44
$ dnf --dump-variables | grep my_test_var
my_test_var = hello44
$ dnf config-manager unsetvar my_test_var

addrepo 添加仓库:先做一个真实可用的本地源——用 createrepo_c 把一个下载好的 rpm 做成仓库,写成 repo 文件,再交给 config-manager 收编:

$ dnf install -y createrepo_c | tail -2
[5/5] Installing createrepo_c-0:1.2.1-5.fc44.x86_6 100% |   6.4 MiB/s | 197.9 KiB |  00m00s
Complete!

$ dnf download tree
Updating and loading repositories:
Repositories loaded.
Downloading Packages:
 tree-0:2.2.1-4.fc44.x86_64             100% | 420.5 KiB/s |  62.7 KiB |  00m00s

$ mv tree-*.rpm /root/demo/dnf/localrepo/
$ createrepo_c /root/demo/dnf/localrepo | tail -2
Pool started (with 5 workers)
Pool finished
$ ls /root/demo/dnf/localrepo/repodata/ | sed -n '1,4p'
0d62093d533cf4ccf5992db32be5ceedfdbe95fd9e481668df7a6b47102baaf8-primary.xml.zst
b775a7aa8278a10a8b3ee6312ff70ad80d8eaead9476670b069bb67475696dc4-filelists.xml.zst
b95fbdf0548a511982b3b94b587296d51af139aaa30e3b534664f02f83d84ec9-other.xml.zst
repomd.xml

$ cat > /root/demo/dnf/local.repo <<'EOF'
[demo-local]
name=Demo Local Repo
baseurl=file:///root/demo/dnf/localrepo
enabled=1
gpgcheck=0
EOF

$ dnf config-manager addrepo --from-repofile=file:///root/demo/dnf/local.repo
 file:///root/demo/dnf/local.repo       100% |   0.0   B/s |  95.0   B |  00m00s
$ dnf repolist
repo id               repo name
demo-local            Demo Local Repo
fedora                Fedora 44 - x86_64
fedora-cisco-openh264 Fedora 44 openh264 (From Cisco) - x86_64
updates               Fedora 44 - x86_64 - Updates
$ ls -l /etc/yum.repos.d/ | grep local
-rw-r--r-- 1 root root   95 Oct 17 00:18 local.repo

从"仅本地源"安装验证闭环(先把 tree 卸掉):

$ dnf remove -y tree | tail -1
Complete!

$ dnf --disablerepo='*' --enablerepo=demo-local install -y tree
Updating and loading repositories:
 Demo Local Repo                        100% |   2.3 MiB/s |   2.4 KiB |  00m00s
Repositories loaded.
Package Arch   Version        Repository      Size
Installing:
 tree   x86_64 0:2.2.1-4.fc44 demo-local 120.0 KiB

Transaction Summary:
 Installing:         1 package

Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 120 KiB extra will be used (install 120 KiB, remove 0 B).
[1/1] tree-0:2.2.1-4.fc44.x86_64        100% |   0.0   B/s |  62.7 KiB |  00m00s
--------------------------------------------------------------------------------
[1/1] Total                             100% |   0.0   B/s |  62.7 KiB |  00m00s
Running transaction
[1/3] Verify package files              100% |   0.0   B/s |   1.0   B |  00m00s
[2/3] Prepare transaction               100% | 111.0   B/s |   1.0   B |  00m00s
[3/3] Installing tree-0:2.2.1-4.fc44.x8 100% |   4.4 MiB/s | 121.4 KiB |  00m00s
Warning: skipped OpenPGP checks for 1 package from repository: demo-local
Complete!
$ rpm -q tree
tree-2.2.1-4.fc44.x86_64

清理演示仓库:

$ dnf remove -y tree | tail -1
Complete!
$ rm -f /etc/yum.repos.d/demo-local.repo /etc/yum.repos.d/local.repo
$ dnf repolist
repo id               repo name
fedora                Fedora 44 - x86_64
fedora-cisco-openh264 Fedora 44 openh264 (From Cisco) - x86_64
updates               Fedora 44 - x86_64 - Updates

解读与 dnf4 迁移对照表:

操作dnf4 写法dnf5 写法(本文实测)持久化位置
启用仓库config-manager --set-enabled Xconfig-manager enable X/etc/dnf/repos.override.d/99-config_manager.repo
禁用仓库config-manager --disable Xconfig-manager disable X同上
改仓库选项config-manager --setopt=X.opt=vconfig-manager setopt X.opt=v同上
改 main 配置config-manager --setopt=main.opt=v不支持,直接编辑 /etc/dnf/dnf.conf/etc/dnf/dnf.conf
加仓库config-manager --add-repo URLconfig-manager addrepo --from-repofile=仓库定义文件/etc/yum.repos.d/
设变量config-manager --setvar=X vconfig-manager setvar X=v/etc/dnf/vars/

Warning: skipped OpenPGP checks for 1 package from repository: demo-local 是 gpgcheck=0 的正常代价——自建源没有签名,dnf 提示但放行。公网第三方源不要学这个写法,保持 gpgcheck=1 并配好 gpgkey。

💡 override 层是 dnf5 的"配置 git stash":repos.override.d/ 里的文件由 libdnf5 生成并声明"勿手改",加载顺序在 .repo 文件之后,因此 config-manager 的改动总是生效且可整体追溯(unsetopt 即删行)。手工改 .repo 文件与 config-manager 两套写法并存时,以 override 层为准——排障时 dnf --dump-repo-config=<repo> 看到的才是"最终生效值"。

3.20 常用全局选项合集

本节集中实测横跨所有子命令的全局选项,每个都给出真实回显与结论。

(1)交互确认与 -y/--assumeyes、--assumeno。不带 -y 时会询问(printf 'n\n' 模拟手输 no):

$ printf 'n\n' | dnf install tree
Updating and loading repositories:
Repositories loaded.
Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 120 KiB extra will be used (install 120 KiB, remove 0 B).
Is this ok [y/N]: Operation aborted by the user.
$ echo $?
1

-y 与 --assumeno 同时给出时,no 优先:

$ dnf install -y --assumeno tree
Updating and loading repositories:
Repositories loaded.
Package Arch   Version        Repository      Size
Installing:
 tree   x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Installing:         1 package

Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 120 KiB extra will be used (install 120 KiB, remove 0 B).
Operation aborted by the user.
$ echo $?
1

$ dnf -y install tree | tail -3
[3/3] Installing tree-0:2.2.1-4.fc44.x8 100% |   3.0 MiB/s | 121.4 KiB |  00m00s
Complete!
$ rpm -q tree
tree-2.2.1-4.fc44.x86_64

结论:-y 脚本标配;--assumeno 是只读试跑;两者冲突时保守者胜,不会出现"既 -y 又被否"的歧义行为。

(2)mark:安装原因标记。装进来的包默认 reason 为 User,依赖为 Dep;mark 手工改档,直接影响 autoremove 的生死簿:

$ dnf mark user tree
Package "tree-2.2.1-4.fc44.x86_64" is already installed with reason "User".

Nothing to do.

$ dnf repoquery --userinstalled tree
tree-0:2.2.1-4.fc44.x86_64

(tree 已是 User 档,mark 报"已是该原因"。repoquery --userinstalled 可列出全部用户显式安装的包,做主机基线比对时很有用。)

(3)-q/--quiet 安静模式:抑制状态性输出(Updating and loading repositories: 那两行没了),查询内容保留:

$ dnf -q info cowsay | sed -n '1,6p'
Available packages
Name           : cowsay
Epoch          : 0
Version        : 3.8.4
Release        : 5.fc44
Architecture   : noarch

(4)-C/--cacheonly 纯缓存模式:不联网,只用本地缓存,弱网/断网巡检可用:

$ dnf -C info cowsay | sed -n '1,8p'
Updating and loading repositories:
Repositories loaded.
Available packages
Name           : cowsay
Epoch          : 0
Version        : 3.8.4
Release        : 5.fc44
Architecture   : noarch
$ echo $?
0

(缓存内已有该包元数据,查询成功;若 -C 时元数据缺失或强制过期,命令会直接失败——这是判断"缓存是否够用"的探针。)

(5)--exclude 排除通配:

$ dnf remove -y tree | tail -1
Complete!
$ dnf install --assumeno --exclude=tree tree
Updating and loading repositories:
Repositories loaded.
Failed to resolve the transaction:
Argument 'tree' matches only excluded packages.
$ echo $?
1

(6)--disablerepo / --enablerepo 临时仓库选择(等价别名 --disable-repo/--enable-repo):

$ dnf --disablerepo=updates repolist
repo id               repo name
fedora                Fedora 44 - x86_64
fedora-cisco-openh264 Fedora 44 openh264 (From Cisco) - x86_64

$ dnf --disablerepo='*' --enablerepo=fedora repolist
repo id repo name
fedora  Fedora 44 - x86_64

(7)--skip-unavailable 与 --skip-broken:跳过"仓库里没有的包"实测有效,但跳不过"无匹配"这类求解错误:

$ dnf install --skip-unavailable --assumeno nosuchpkg-404
Updating and loading repositories:
Repositories loaded.
No match for argument: nosuchpkg-404

Nothing to do.
$ echo $?
0

$ dnf install --skip-broken --assumeno nosuchpkg-404
Updating and loading repositories:
Repositories loaded.
Failed to resolve the transaction:
No match for argument: nosuchpkg-404
You can try to add to command line:
  --skip-unavailable to skip unavailable packages
$ echo $?
1

结论:--skip-unavailable 用于"装 A B C,C 可能没有"的幂等脚本(这里无匹配也返回 0);--skip-broken 解决的是依赖冲突场景(某包依赖残缺时跳过它继续),两者不要混为一谈。

(8)--best:强制选"最高可用版本"候选:

$ dnf install --best --assumeno tree
Updating and loading repositories:
Repositories loaded.
Package Arch   Version        Repository      Size
Installing:
 tree   x86_64 0:2.2.1-4.fc44 fedora     120.0 KiB

Transaction Summary:
 Installing:         1 package

Total size of inbound packages is 63 KiB. Need to download 63 KiB.
After this operation, 120 KiB extra will be used (install 120 KiB, remove 0 B).
Operation aborted by the user.

(单包场景看不出差别;多仓库多版本并存、或指定 tree-2.1* 这类模糊 spec 时,--best 保证不为了"少动依赖"而选旧版。默认 best=0,即允许求解器挑非最优解以减少事务规模。)

(9)--dump-main-config / --dump-variables:排障透视镜:

$ dnf --dump-variables | sed -n '1,6p'
======== Variables: ========
arch = x86_64
basearch = x86_64
releasever = 44
releasever_major =
releasever_minor =

$ dnf --dump-main-config | sed -n '1,18p'
======== Main configuration: ========
allow_downgrade = 1
allow_vendor_change = 1
assumeno = 0
assumeyes = 0
autocheck_running_kernel = 1
bandwidth = 0
best = 0
bugtracker_url = https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&component=dnf
build_cache = 1
cachedir = /var/cache/libdnf5
cacheonly = none
check_config_file_age = 1
clean_requirements_on_remove = 1
color = auto
color_list_available_downgrade = dim,magenta
color_list_available_install = bold,cyan
color_list_available_reinstall = bold,green

顺带实测单次生效的 --setopt(注意:不带 main. 前缀、单次事务级生效,与 config-manager setopt 的持久化不同):

$ dnf --setopt=install_weak_deps=False --dump-main-config | grep '^install_weak_deps'
install_weak_deps = 0

$ dnf --setopt=main.keepcache=True --dump-main-config | grep -E '^keepcache'
No matching repositories for main. Add "--help" for more information about the arguments.

结论:--setopt=选项名=值 可单次改 main 级配置;--setopt=main.选项名=值 这个 dnf4 习惯写法在 dnf5 全局选项里同样不被接受。

(10)leaves / check / changelog:三个体检小工具:

$ dnf leaves | sed -n '1,8p'
- bzip2-0:1.0.8-23.fc44.x86_64
- createrepo_c-0:1.2.1-5.fc44.x86_64
- dnf5-0:5.4.3.0-2.fc44.x86_64
  dnf5-plugins-0:5.4.3.0-2.fc44.x86_64
- gawk-0:5.3.2-3.fc44.x86_64
- rootfiles-0:9.0-6.fc44.noarch
- shadow-utils-2:4.19.0-7.fc44.x86_64
- sudo-0:1.9.17-8.p2.fc44.x86_64

$ dnf check
$ echo $?
0

$ dnf changelog tree | sed -n '5,12p'
>>> Status code: 404 for https://mirrors.qlu.edu.cn/fedora/releases/44/Everything/x86_64/os/repodata/6a37d36914955dc65cf6dc037c37dcf00c64ded464dc34164a674bf65fa16927-comps-Everything.x86_64.xml.zst (IP: 210.44.151.62) - https://mirrors.qlu.edu.cn/fedora/releases/44/Everything/x86_64/os/repodata/6a37d36914955dc65cf6dc037c37dcf00c64ded464dc34164a674bf65fa16927-comps-Everything.x86_64.xml.zst
Listing all changelogs
Changelogs for tree-2.2.1-4.fc44.x86_64
* Sat Jan 17 12:00:00 2026 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.1-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild

* Thu Dec 04 12:00:00 2025 Stewart Smith <trawets@amazon.com> - 2.2.1-3
- Fix Source URL

解读:leaves 列叶子包(不再被任何已装包依赖的顶层包,行首 - 是列表标记),裁剪系统时从叶子下手;check 校验本地 rpmdb 一致性(退出码 0 即健康,排障见 FAQ);changelog 展示包的更新日志——注意它顺带暴露了一个真实世界的瑕疵:镜像的 comps 元数据 404(详见 FAQ),dnf 自动容错跳过,不影响 changelog 输出。

(11)dnf5 的日志文件:

$ ls -l /var/log/dnf5* | sed -n '1,3p'
-rw-r--r-- 1 root root  340149 Oct 17 00:21 /var/log/dnf5.log
-rw-r--r-- 1 root root 1048511 Oct 17 00:18 /var/log/dnf5.log.1
$ tail -2 /var/log/dnf5.log
2026-10-17T00:18:49+0000 [660] DEBUG No modules metadata available for repo fedora
2026-10-17T00:18:49+0000 [660] INFO DNF5 finished

/var/log/dnf5.log 按 1 MiB 轮转(.1~.4),时间戳带时区,DEBUG 级信息对定位"事务为什么这么解"很有用;更细的求解过程可用全局选项 --debugsolver 导出。

四、实战示例

以下五个场景把第三章的命令串成完整工作流,全部在实测环境跑通过。

4.1 新机初始化与补丁巡检

目标:一台刚装好的 Fedora 服务器,完成"元数据就绪 → 巡检 → 决策 → 执行 → 验证"闭环。

# 1. 元数据就绪(新机缓存为空,会全量下载)
dnf makecache

# 2. 巡检:只查不动,退出码 100=有更新 0=最新
dnf check-update
# 输出见 3.13:15 个可升级包,含 dnf5 自身与 glibc

# 3. 决策:先全量预演看清单与体积
dnf upgrade --assumeno
# 输出见 3.12:21 MiB 下载、67 MiB 落盘

# 4. 执行:夜间窗口全量升级
dnf -y upgrade

# 5. 验证:抽查关键包版本 + 确认无遗留孤儿
rpm -q dnf5 glibc
dnf autoremove --assumeno

第 4、5 步的实测回显(真实跑完全量升级):

$ dnf -y upgrade
Updating and loading repositories:
Repositories loaded.
Package                                  Arch   Version                     Repository                            Size
Upgrading:
 ca-certificates                         noarch 0:2026.2.90_v9.0.317-1.fc44 updates                            2.7 MiB
   replacing ca-certificates             noarch 0:2025.2.80_v9.0.304-7.fc44 0eae96ab45874228a86a12a132e699ed   2.7 MiB
 curl                                    x86_64 0:8.18.0-14.fc44            updates                          480.0 KiB
   replacing curl                        x86_64 0:8.18.0-8.fc44             0eae96ab45874228a86a12a132e699ed 480.0 KiB
 ……(中间 61 个升级包略,结构同上)……
[63/65] Removing glibc-0:2.43-8.fc44.x8 100% |   7.3 KiB/s | 105.0   B |  00m00s
[64/65] Removing glibc-minimal-langpack 100% |  16.3 KiB/s | 100.0   B |  00m00s
[65/65] Removing glibc-common-0:2.43-8. 100% |  38.0   B/s |  52.0   B |  00m01s
Complete!

$ rpm -q dnf5 glibc
dnf5-5.4.6.0-1.fc44.x86_64
glibc-2.43-9.fc44.x86_64

$ dnf autoremove --assumeno
Nothing to do.
$ echo $?
0

验证手段解读:rpm -q 的版本号(dnf5-5.4.6.0、glibc-2.43-9)正是 3.13 巡检清单里 updates 源给出的目标版本,说明升级闭环完成;autoremove 返回 Nothing to do.(退出码 0)说明没有孤儿遗留。另注意到全量升级把 dnf5 自身从 5.4.3.0 升到了 5.4.6.0——第三章全部回显都摄于升级前的 5.4.3.0,本节回显摄于该次升级执行过程,属同一环境的真实记录。

4.2 内网离线打补丁(download --resolve 工作流)

目标:外网机下载完整依赖闭包,拷入无外网的内网机安装。

# 外网机:下载 cowsay 及其全部未装依赖(64 个 rpm 落到当前目录)
cd /root/demo/dnf
dnf download --resolve cowsay
# 实测 64 个 rpm,清单见 3.16

# 打包传内网(scp/光碟/U盘均可)
tar cf cowsay-bundle.tar *.rpm

# 内网机:本地 rpm 直装(回显见下)
dnf install -y ./tree-2.2.1-4.fc44.x86_64.rpm

本地 rpm 直装的实测回显(用 tree 单包演示,cowsay 等多依赖包同理):

$ dnf install -y ./tree-2.2.1-4.fc44.x86_64.rpm
Updating and loading repositories:
Repositories loaded.
Total size of inbound packages is 63 KiB. Need to download 0 B.
After this operation, 120 KiB extra will be used (install 120 KiB, remove 0 B).
Running transaction
[1/3] Verify package files              100% |   0.0   B/s |   1.0   B |  00m00s
[2/3] Prepare transaction               100% | 111.0   B/s |   1.0   B |  00m00s
[3/3] Installing tree-0:2.2.1-4.fc44.x8 100% |   3.8 MiB/s | 121.4 KiB |  00m00s
Warning: skipped OpenPGP checks for 1 package from repository: @commandline
Complete!
Installing:
 tree   x86_64 0:2.2.1-4.fc44 @commandline 120.0 KiB

Transaction Summary:
 Installing:         1 package

$ rpm -q tree
tree-2.2.1-4.fc44.x86_64

三个实测细节:Repository 列显示 @commandline——本地文件不经过任何仓库;Need to download 0 B——rpm 已在本地,只解依赖;Warning: skipped OpenPGP checks for 1 package from repository: @commandline——本地包默认跳过签名校验,这就是为什么外网下载的包要在可信渠道获取。事务摘要出现在 Complete! 之后是 3.10 所述 stderr/stdout 交缠现象,非异常。

验证手段:内网机 rpm -q 版本与外网机一致;若内网机提示缺依赖,说明两机 rpmdb 基线差异过大,改用 --alldeps 重新在外网机下载全量依赖。dnf download --url cowsay 可先把下载地址甩给同事复核,不用先落盘。

4.3 自建本地仓库并收编(createrepo_c + config-manager)

目标:把一批 rpm 做成正式仓库,走 dnf 标准流程管理(4.2 的进阶版,可挂内网 HTTP 长期服务)。

# 1. 备料:收集 rpm 到仓库目录
mkdir -p /srv/repo/local
cp /root/demo/dnf/*.rpm /srv/repo/local/

# 2. 生成元数据
createrepo_c /srv/repo/local
# 实测输出 Pool started (with 5 workers) / Pool finished

# 3. 写 repo 定义
cat > /etc/yum.repos.d/demo-local.repo <<'EOF'
[demo-local]
name=Demo Local Repo
baseurl=file:///srv/repo/local
enabled=1
gpgcheck=0
EOF

# 4. 刷新缓存并验证
dnf clean metadata && dnf makecache
dnf repo info demo-local
dnf --disablerepo='*' --enablerepo=demo-local list --available

# 5. 装一个验证闭环,然后看仓库报表
dnf --disablerepo='*' --enablerepo=demo-local install -y tree
dnf repoinfo

第 4 步的实测回显:

$ dnf --disablerepo='*' --enablerepo=demo-local list --available
Updating and loading repositories:
Repositories loaded.
Available packages
tree.x86_64 2.2.1-4.fc44 demo-local

$ dnf repo info demo-local
Updating and loading repositories:
Repositories loaded.
Repo ID              : demo-local
Name                 : Demo Local Repo
Status               : enabled
Priority             : 99
Cost                 : 1000
Type                 : available
Metadata expire      : 172800 seconds (last: 2026-10-17 00:32:42)
Skip if unavailable  : true
Config file          : /etc/yum.repos.d/demo-local.repo
URLs                 :
  Base URL           : file:///srv/repo/local
OpenPGP              :
  Verify repodata    : false
  Verify packages    : false

实测要点:仓库目录更新后重跑 createrepo_c 即可(增量更新加 --update);list --available 输出行尾的仓库名 demo-local 证明包确实来自新仓库;repo info 里 Verify packages: false 对应 gpgcheck=0;若要走 HTTP,把 baseurl 改为 http://内网机地址/repo/local 并在仓库机起 nginx/httpd。第 5 步的安装回显与 3.19 的 demo-local 安装一致,此处不重复贴出。

4.4 误操作回滚(history undo / rollback 决策)

目标:凌晨批量安装脚本装错了包集合,需要精准回退。决策树:只撤销一条命令 → undo 那条命令的事务号;撤销某时间点之后的全部 → rollback 到那个时间点之前最后一个好事务号。

# 1. 找现场:按命令行关键字定位事务号
dnf history list | grep 'install -y sl'
# 实测:32 dnf install -y sl

# 2. 体检:确认该事务干了什么、前后 rpmdb 哈希
dnf history info 32
# 实测:仅 Install sl-0:5.02-25.fc44.x86_64,Status Ok

# 3. 撤销单事务(摘要与实测回显见 3.18)
dnf -y history undo 32
# 实测:Removing sl,Complete!,figlet 不受影响

# 4. 更大范围:回滚到基线事务 30(撤销其后全部)
dnf -y history rollback 30
# 实测:Removing figlet,Complete!

# 5. 复盘:undo/rollback 各留痕一条,last 与区间写法可用
dnf history list | sed -n '1,5p'
dnf history info last
dnf history info 30..31

验证手段:rpm -q 逐包确认;dnf history info <撤销事务号> 的 Begin rpmdb 哈希应等于被撤销事务的 Begin rpmdb(系统状态精确回到原点,3.18 实测数据即如此)。

4.5 磁盘瘦身三连(clean + autoremove + leaves)

目标:/var 告警后的标准瘦身流程,按"安全 → 谨慎 → 人工"排序。

# 1. 无风险:清缓存(元数据 + 已下载 rpm)
dnf clean all
du -sh /var/cache/libdnf5
# 实测:263 MiB 清空

# 2. 低风险:清孤儿依赖(先预演过目)
dnf autoremove --assumeno
dnf -y autoremove
# 实测:63 包 / 28 MiB(3.11)

# 3. 人工决策:叶子包里挑不再需要的显式卸载
dnf leaves
dnf remove -y createrepo_c   # 例:临时工具用完即删

验证手段:df -h /var 前后对比;dnf leaves 复查叶子列表变化;切勿对 leaves 清单一把梭 dnf remove——叶子不等于没用(sudo、gawk 都在其中),必须逐个判断。

五、注意事项与常见问题

Q1:check-update 退出码 100 算失败吗? 不算。约定:0=无更新,100=有可用更新,1=真错误。监控脚本要把 100 当作正常分支处理(见 3.13)。

Q2:dnf help <命令> 报 Unknown argument? dnf5 移除了 help 子命令(实测退出码 2,3.13),改用 dnf <命令> --help;报错里提示的 dnf5 install 'dnf5-command(help)' 是一个第三方补丁插件,按需自选。

Q3:dnf list installed 为什么报 No matching packages? installed 不带 -- 时被当作包名模式。规范写法 dnf list --installed;若用旧写法必须跟包名:dnf list installed tree(3.6 有完整实测)。

Q4:config-manager setopt main.keepcache=True 报 Option "keepcache" not found? dnf5 的 config-manager setopt 只支持仓库级选项,main 级配置它管不了(实测回显见 3.19)。改 main 配置:直接编辑 /etc/dnf/dnf.conf,或用单次生效的 dnf --setopt=install_weak_deps=False(注意不带 main. 前缀,实测 3.20 第 9 条)。

Q5:config-manager enable 之后,为什么 .repo 文件没变? dnf5 把改动写进覆盖层 /etc/dnf/repos.override.d/99-config_manager.repo(文件头注明"Generated by libdnf5, Do not modify manually"),加载优先级高于 /etc/yum.repos.d/。排障时以 dnf --dump-repo-config=<repo> 为准(3.19)。

Q6:makecache 时镜像报 404(comps 元数据),要紧吗? 实测在 changelog 场景撞到过镜像 comps 元数据 404(完整逐字回显见 3.20 第 10 条,含真实镜像 IP)。这是个别镜像的 repodata 目录不全,dnf 容错后元数据照常可用,命令照常成功。若 404 密集到主元数据(primary/filelists)失败,换用其他镜像或稍后重试;国内镜像同步高峰期(发版后数日)最易出现。

Q7:不同命令打印的下载地址不一样(qlu/nyist 镜像)? metalink 调度按当次测速选镜像,repo info 展示的候选首位、download --url 打印的地址都可能随时间变化,属正常现象(3.3 与 3.16 的实测地址就不同)。要钉死地址就自建源用 baseurl。

Q8:采集 dnf 输出到日志,顺序怎么乱了? dnf5 把进度条与提示写 stderr、事务摘要写 stdout,管道后顺序会交叉(3.10 两个回显对比可见)。要原始顺序:dnf <子命令> 2>&1 | tee dnf.log;只关心结果:dnf -q <子命令>。

Q9:group list --installed 里找不到明明装过的组? 隐藏组(Uservisible: no)装上也不显示,实测 fonts 组安装 137 个包后该列表仍为空(3.17)。确认状态用 dnf group info <组id> 看 Installed 字段,或 dnf group list --hidden --installed。

Q10:downgrade 报 The lowest available version of the "tree.x86_64" package is already installed, cannot downgrade it.,且退出码是 0? 官方源只有最新版时无版本可降,dnf5 把它当"无事可做"(退出码 0)。真降级要给低版本来源:dnf --releasever=43 downgrade <包> 指向上一版源(3.15 全流程实测)。整系统回退没有官方路径,只有向前升级。

Q11:history undo 失败或结果与预期不符? undo 是对当下仓库重新求解的反向事务,不是存档回放:涉及包已下架、或之后事务动过同一批文件,都可能失败或触发连带改动。 undo 前必做三件事:dnf history info <id> 过目清单、备份 /var/lib/dnf/history、小范围先试。rollback 范围更大,慎之又慎(3.18)。

Q12:autoremove 会误删我手工 rpm -ivh 装的包吗? 不会。autoremove 只动 reason 为 Dep 的包;手工 rpm 装的包 reason 为 User(外部原因),不在清理范围。可用 dnf repoquery --userinstalled 审计名单,用 dnf mark user <包> 给"其实是手动维护"的包人工改档(3.20 第 2 条)。

Q13:装包时提示 skipped OpenPGP checks 是不是被攻击了? 只在该仓库配置 gpgcheck=0 时出现(本文自建 demo-local 源即如此,3.19)。公网第三方源保持 gpgcheck=1 + gpgkey= 配置;临时跳过签名用全局 --nogpgcheck(等价 --no-gpgchecks),用完即弃。

Q14:怎么确认 rpmdb 没被人手工动过? 两条腿:dnf check 做一致性体检(健康时退出码 0、无输出,3.20);比对相邻事务的 dnf history info 里 End rpmdb 与下一条 Begin rpmdb 哈希是否一致,不一致说明中间有 dnf 体系外的 rpmdb 变更(3.18)。

Q15:镜像源能否指定国内教育网/企业源? 可以,两种姿势:临时用 --setopt 改 metalink/baseurl,或自建源(4.3)。Fedora 官方 repo 默认走 mirrors.fedoraproject.org 的 metalink 服务做全球调度(repo info 的 35 more 即镜像池,3.3),国内直连速度不佳时再动手。

Q16:dnf5 的日志在哪、多大、怎么轮转? /var/log/dnf5.log(主日志,1 MiB 轮转,保留 .1~.4)与 /var/log/dnf5.lib.log(库级)。排障顺序:先 history(事务级)→ dnf5.log(命令级 DEBUG/INFO)→ --debugsolver(求解级,导出专用目录)。

六、参考链接