依存関係なしで手動でインストールした最上位のパッケージを一覧表示する


12

を使用して手動でインストールされたパッケージを表示するにはapt、次のような多くの方法があります。

apt-mark showmanual

しかし、その出力が多すぎる場合があります。たとえば、ユーザーが手動でパッケージをインストールした場合foo

apt-get install foo

...とにfoo依存しbarているbaz場合は、次のapt-mark showmanualように出力されます。

bar
baz
foo

どのように我々はトップレベル手動でインストールしたパッケージ(のみ一覧表示することができますつまりは foo)それらの依存関係なしで(すなわちないbaz、もbar)?


次のコードは機能するようですが、GNU が数百回parallel呼び出すapt-rdependsのは遅すぎます(4コアCPUで3時間)。

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

回答:


9

これは、Python apt APIを使用して行うことができます。表示さapt-mark showmanualれるパッケージは、がtrueとfalse apt.cache.Cache()であるパッケージとまったく同じです。ただし、依存関係を処理する方が簡単です。is_installedis_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時間のコードのスーパーセットを出力しますが、initandのような驚きはありgrepません(おそらく、適切なデータが破損していますか?)。また、ライブラリーが多すぎます。OTOH、私の3時間のコード、そこにあるはずのいくつかの項目、上記のpythonコードが出力する項目を見逃しています。不足しているアイテムがでインストールされなかった可能性がありaptます。
agc 2017年

@agcそれはおそらく私が再帰しなかったためです。週末の後で再帰オプションを試します。ただし、再帰があっても、apt-rdependsを繰り返し呼び出すよりもずっと高速になると思います
muru

上記のpythonコードは、私のコード(3時間)より3600倍高速です(つまり、3秒かかりました)。再帰バージョンのテストを楽しみにしています...
agc

3

次のシェルスクリプトは、インストールされているすべての依存関係の親を検索します。

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このスクリプトで使用しました。依存関係のない最後にマーカーを追加すると、マーカーは結果に依存関係のない最後のエントリになると思います。したがって、依存関係のない最後のパッケージと依存関係のある最初のパッケージを区別できます。

このソリューションの1つの問題に気づきました:
依存関係グラフに循環があります。これらのエントリはによって無視されtsortます。


2

次のように、第1レベルの依存関係なしで手動でインストールされたすべてのパッケージを見つけることができます。

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

はい、スクリプトは完全な依存関係ツリーを考慮していません。より多くの階層レベルに適合させることもできます。
シーラー2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.