我有一个 Fedora 系统 (A),我在其中安装了一些软件包。现在我想在另一台计算机 (B) 上安装 Fedora,并在其上安装相同的软件包。
用 Debian 的术语来说,我想要完成这样的事情:
$ dpkg --get-selections > pkg_sel_host_a # on host_a
$ dpkg --set-selections < pkg_sel_host_a # on host_b
但说实话,我真的想要一个更好的方法来在新的 Fedora 19 系统上选择相同的软件包 (B):我只想安装系统 A 中在 dnf install
(或yum install
) 命令行上明确提到的软件包 - 而不是那些作为依赖项安装的!
为什么?因为也许依赖项已经改变 - 而且我不想在新系统上安装过时的依赖项。另外,当我删除软件包时,我也想删除(可能)然后不需要的自动安装的依赖项(即孤立项)。
我发现dnf list installed
- 但它不会显示是否显式选择了软件包或由于依赖关系而刚刚安装了软件包。
我如何获取 Fedora 上的这些信息?
Fedora/dnf 复制软件包选择的方式是什么?
答案1
从 Fedora 26 开始,DNFrepoquery
子命令支持有一个用于列出所有用户安装的软件包的新选项:
$ dnf repoquery --qf '%{name}' --userinstalled \
| grep -v -- '-debuginfo$' \
| grep -v '^\(kernel-modules\|kernel\|kernel-core\|kernel-devel\)$' > pkgs_a.lst
与其他方法相比,它还列出了所有 debuginfo 包。上面示例中的附加 grep 会将它们过滤掉。
要在主机 B 上安装列表:
$ < pkgs_a.lst xargs dnf -y install
地下城API
对于最新的 Dnf 版本(例如 Fedora >= 23),可以通过 Dnf Python API 查询包数据库以获取用户安装的包名称:
$ python3 -c 'import dnf; b = dnf.Base(); b.fill_sack(); \
l = sorted(set(x.name for x in b.iter_userinstalled() \
if not x.name.endswith("-debuginfo") \
and x.name not in \
["kernel-modules", "kernel", "kernel-core", "kernel-devel"] )); \
print("\n".join(l)) ' > pkgs_a.lst
# dnf install $(cat pkgs_a.lst) # on host_b
默认情况下,dnf install
如果一个或多个包不再可用,则中止。或者,dnf可以被强迫安装所有剩余的:
# dnf install --setopt=strict=0 $(cat pkgs_a.lst) # on host_b
附:将上面的代码和更多内容放入user-installed.py
它还支持其他发行版。
历史用户安装
在 Fedora 23 及更高版本上,Dnf 提供
# dnf history userinstalled
列出所有用户安装的软件包的命令。截至 2016 年 11 月,其有用性有限因为没有办法控制它的输出并且它打印完全合格的包(即包括版本信息)。
用户安装的限制
请注意,将软件包标记为用户安装对某些 Fedora 版本有一些限制,对于 Fedora 23 左右时代的系统(从 2015 年 11 月左右开始),以下问题是相关的:
- 已安装的软件包不包括通过 GUI
- 已安装的软件包通过命令未找到处理程序不包括在内
- 默认安装的一些软件包(由 anaconda 提供)被包含在内
重新查询
在较旧的 Fedora 系统上,Dnf、Dnf APIdnf history userinstalled
不可用,可以使用重新查询相反,例如:
$ repoquery --installed \
--qf '%{n} | %{yumdb_info.reason} | %{yumdb_info.installed_by}' --all \
| awk -F'|' ' $2 ~ /user/ && ($3 != 4294967295) { print $1 }' \
| sort -u > pkgs_a.lst
第二个 awk 条件用于排除安装程序安装的软件包。安装程序的用户 ID 显然存储为 4294967295 - 或者您可以编写类似($3 == 0 || $3 == your-user-id)
.
请注意,此命令适用于 Fedora 版本 21 之前的版本 - 但例如不适用于版本 23,因为该命令repoquery
已替换为dnf repoquery
.和dnf repoquery
不理解%{yumdb_info.reason}
标签。
答案2
最简单且行之有效的方法是:
yum-debug-dump => gives file.
yum-debug-restore <file-from-debug-dump>
...其工作方式与获取/设置选择 dpkg 命令 AIUI 非常相似。另请注意,如果您要重播历史记录,可以使用:
yum history addon-info last saved_tx => gives file
yum load-tx <file-from-addon-info>
...而不必自己解析它。
答案3
灵感来自可持续发展管理的回答我想出了以下yum history
基于的解决方案:
获取所有 yum 安装事务(即无升级)的所有详细历史记录,不包括作为初始安装程序操作的一部分执行的事务(我的系统上的事务 1 和 2,归因于用户“系统”):
$ yum history list all | awk -F'|' \
'$4 ~ /Install/ && $2 !~ /System/ {print $1}' \
| xargs yum history info > yum_history
过滤显式安装的软件包并切断版本前缀。
$ < yum_history grep '[^-]\<Install\>' | \
awk '{ print $2 }' \
| sed 's/\(-[0-9]\+:\|-[0-9]\+\.[0-9]\|-[0-9]\+-\|-[0-9]\+git\).\+\(\.fc1[1-7]\.\|\.noarch\).*$//' \
| sort > hist_pkg_list
需要丑陋的正则表达式来匹配各种版本后缀。
结果在我的系统上看起来相当不错。
与重新查询ansatz(在我的系统上):
方法#包 ―――――――――――――――――――――――――― 重新查询 569 repoquery-2nd 216 百胜历史 214
(我通过 sort -u 管道传输 repoquery 结果)
为什么会有差异?因为 repoquery 包含事务 1 和事务 2 中的所有软件包,即由 Fedora 安装程序安装的所有软件包。这解释了为什么 repoquery 包含提到的包 xorg-x11- drv-mga 和朋友。
比较 repoquery-2nd 和 yum-history 表明 repoquery-2nd 更准确 - 它不包括一些已经删除的软件包。此外,它似乎还包括一些来自“yum update”操作的软件包(在我的系统上有 2 个)。
警告
上述基于历史记录的方法仅列出系统整个生命周期内所有显式安装的软件包。它不会平衡在以后的事务中删除的那些包。因此,此方法需要对结果进行一些手动管理,并且只能在repoquery
不可用的系统上使用。
答案4
dnf repoquery --qf "%{name}" --userinstalled > userinstalled.txt