列出顶级手动安装的软件包,不依赖于它们


12

有很多方法可以显示使用手动安装的软件包apt,例如:

apt-mark showmanual

但是有时候输出的太多了。例如,如果用户手动安装软件包foo

apt-get install foo

...并foo取决于barbaz,然后apt-mark showmanual将输出:

bar
baz
foo

我们如何只列出顶级手动安装的软件包( foo),而不列出其依赖项(即,不是bazbar)?


以下代码似乎可以工作,但是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

嗯 答案和OP代码是如此不同,并且返回的数据有些不同,以至于我对于哪种方法的数据最正确感到有些困惑。也许需要一个调查答案,从一个最小的测试系统开始,并一次添加一些程序,以查看输出的变化方式和时间。
AGC

Answers:


9

这可以使用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))

即使这样,也列出了一些我不希望在其中看到的软件包(initgrep?!)。


在我的系统上,该代码输出了我3个小时代码的超集,但没有显示诸如init和的惊奇grep(也许您的apt数据已损坏?),还显示了太多的库。太太,我的3小时代码遗漏了一些应该在上面的python代码,这些代码是上面代码打印的。可能缺少的项未安装apt
agc

@agc可能是因为我没有递归。周末之后,我将尝试递归选项。即使进行递归,我也希望这比重复调用apt-rdepends更快
穆鲁

上面的python代码比我的代码(3小时)快3600倍(即花了3秒钟)。期待测试递归版本...
AGC

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


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)

快多了。这将输出主要是OP代码的超集,但也会遗漏一些信息,例如dasher程序包。在我的系统上,OP代码通过sort -V输出475行输出,muru的代码输出914行(包括dasher),此答案的代码输出995行。
agc

是的,我的脚本没有考虑完整的依赖关系树。您可以尝试使其适应更多层次结构级别。
密封者18/09/26
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.