![列出顶级手动安装的软件包,不包含其依赖项](https://linux22.com/image/112854/%E5%88%97%E5%87%BA%E9%A1%B6%E7%BA%A7%E6%89%8B%E5%8A%A8%E5%AE%89%E8%A3%85%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%EF%BC%8C%E4%B8%8D%E5%8C%85%E5%90%AB%E5%85%B6%E4%BE%9D%E8%B5%96%E9%A1%B9.png)
有很多方法可以显示使用手动安装的软件包apt
,例如:
apt-mark showmanual
但有时这个输出太多了。例如,如果用户手动安装包foo
:
apt-get install foo
...并且foo
依赖于bar
和baz
,然后apt-mark showmanual
将输出:
bar
baz
foo
我们如何只列出顶级手动安装的软件包(IE foo
) 没有它们的依赖关系 (IE不是baz
,也不是bar
)?
下面的代码似乎可以工作,但是GNU parallel
调用apt-rdepends
几百次太慢了,(4核CPU需要三个小时):
apt-mark showmanual |
tee /tmp/foo |
parallel "apt-rdepends -f Depends,PreDepends,Suggests,Recommends {} |
tail +2" 2> /dev/null |
tr -s ' ' '\n' |
grep -v '[():]' |
sort -Vu |
grep -wv -f - /tmp/foo
答案1
这可以使用 Python apt API 来完成。您看到的软件包正是其中的真实apt-mark showmanual
软件包,并且apt.cache.Cache()
is_installed
is_auto_installed
是假的。但是,处理依赖关系更容易:
#! /usr/bin/env python3
from apt import cache
manual = set(pkg for pkg in cache.Cache() if pkg.is_installed and not pkg.is_auto_installed)
depends = set(dep_pkg.name for pkg in manual for dep in pkg.installed.get_dependencies('PreDepends', 'Depends', 'Recommends') for dep_pkg in dep)
print('\n'.join(pkg.name for pkg in manual if pkg.name not in depends))
即使这列出了一些我不希望在那里看到的软件包(init
,grep
?!)。
答案2
您可以找到所有手动安装的没有第一级依赖项的软件包,如下所示:
apt-mark showmanual | sort > manually-installed.txt
apt show $(apt-mark showmanual) 2>/dev/null |
grep -e ^Depends -e ^Pre-Depends > deps1.txt
cat deps1.txt |
sed 's/^Depends: //; s/^Pre-Depends: //;
s/(.*)//g; s/:any//g' > deps2.txt
cat deps2.txt | tr -d ',|' | tr ' ' '\n' | grep -v ^$ |
sort -u > all-dep-packages.txt
grep -v -F -f all-dep-packages.txt manually-installed.txt
您还可以使用以下一行魔术:
apt-mark showmanual | sort | grep -v -F -f <(apt show $(apt-mark showmanual) 2> /dev/null | grep -e ^Depends -e ^Pre-Depends | sed 's/^Depends: //; s/^Pre-Depends: //; s/(.*)//g; s/:any//g' | tr -d ',|' | tr ' ' '\n' | grep -v ^$ | sort -u)
答案3
以下 shell 脚本搜索所有已安装依赖项的父项。
function get_installed_packages() {
apt list --installed | sed 's#/.*##'
}
function get_installed_packages_with_deps() {
dpkg-query --show --showformat '${Package} ${Depends} \
${Pre-Depends}\n' $(get_installed_packages) |
sed 's/ ([^(]*)//g; s/:any\|,//g'
}
function get_package_relations() {
awk '{print $1 " " $1; for(i = 2; i <= NF; i++) print $1 " " $i;}'
}
function add_marker() {
echo "~ ~"
}
function resolve_parents() {
tsort | sed -n '1,/~/ p' | head -n -1
}
(get_installed_packages_with_deps | get_package_relations; add_marker) |
resolve_parents
我tsort
在这个脚本中使用了。我假设在没有依赖关系的末尾添加标记时,该标记也将是结果中没有依赖关系的最后一个条目。因此我可以区分最后一个没有依赖项的包和第一个有依赖项的包。
我注意到这个解决方案的一个问题:
依赖图中存在循环。这些条目将被忽略tsort
。
答案4
看这个答案在 Askubuntu 上apt-mark showmanual
,它使用与 的内容进行比较/var/log/installer/initial-status.gz
:
comm -23 <(apt-mark showmanual | sort -u) <(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u)
这给了我自从全新安装 Ubuntu 以来我手动添加的软件包。