Daftar paket tingkat atas yang diinstal secara manual tanpa ketergantungannya

12

Ada banyak cara untuk menunjukkan paket yang diinstal menggunakan secara manual apt, seperti:

apt-mark showmanual

Tetapi terkadang output itu terlalu banyak. Misalnya jika pengguna menginstal paket secara manual foo:

apt-get install foo

... dan foobergantung pada bardan baz, kemudian apt-mark showmanualakan menampilkan:

bar
baz
foo

Bagaimana kita bisa mendaftar hanya paket tingkat atas yang diinstal secara manual ( yaitu foo ) tanpa ketergantungannya ( mis. Tidak baz, juga bar)?


Kode berikut tampaknya berfungsi, tetapi panggilan GNU beberapa ratus kali terlalu lambat, (tiga jam dengan CPU 4 inti):parallelapt-rdepends

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
agc
sumber
Hmm. Jawabannya, dan kode OP, semuanya sangat berbeda, dan mengembalikan data yang agak berbeda, sehingga saya agak bingung tentang data metode mana yang paling benar. Mungkin jawaban survei diperlukan, mulai dari sistem tes minimal, dan menambahkan beberapa program sekaligus untuk melihat bagaimana dan kapan output bervariasi.
agc

Jawaban:

9

Ini bisa dilakukan dengan menggunakan API Python apt. Paket yang Anda lihat apt-mark showmanualadalah paket apt.cache.Cache()yang is_installedbenar dan is_auto_installedsalah. Tapi, lebih mudah untuk memproses dependensi:

#! /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))

Bahkan ini mencantumkan beberapa paket yang tidak akan saya lihat di sana ( init, grep?!).

muru
sumber
Pada sistem saya bahwa kode menghasilkan superset dari kode 3 jam saya, tetapi tidak menunjukkan kejutan seperti initdan grep, (mungkin data apt Anda rusak?), Juga menunjukkan terlalu banyak perpustakaan. OTOH, kode 3 jam saya kehilangan beberapa item yang seharusnya ada, item yang pythondicetak oleh kode di atas . Mungkin barang yang hilang tidak terpasang apt.
agc
@ Agc itu mungkin karena saya tidak muncul kembali. Saya akan mencoba opsi rekursif setelah akhir pekan. Meskipun dengan rekursi, saya berharap ini lebih cepat daripada memanggil apt-rdepends berulang kali
muru
pythonKode di atas adalah 3600 kali lebih cepat (yaitu butuh 3 detik) daripada kode saya (3 jam). Menantikan pengujian versi rekursif ...
agc
3

Script shell berikut mencari orang tua dari semua dependensi yang diinstal.

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

Saya menggunakan tsortskrip ini. Saya berasumsi bahwa ketika menambahkan marker di akhir tanpa dependensi marker juga akan menjadi entri terakhir tanpa dependensi pada hasil saya. Jadi saya dapat membedakan antara paket terakhir tanpa dependensi dan paket pertama dengan dependensi.

Saya perhatikan satu masalah dengan solusi ini:
Ada siklus dalam grafik ketergantungan. Entri-entri itu diabaikan oleh tsort.

sealor
sumber
2

Anda dapat menemukan semua paket yang diinstal secara manual tanpa tingkat ketergantungan pertama sebagai berikut:

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

Anda juga dapat menggunakan sihir satu garis berikut:

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)
sealor
sumber
Lebih cepat. Ini menghasilkan sebagian besar superset dari kode OP, tetapi juga melewatkan beberapa, seperti dasherpaket. Pada sistem saya, kode OP disalurkan melalui sort -Voutput 475 baris, kode muru menghasilkan 914 baris, (termasuk dasher), dan kode jawaban ini menghasilkan 995 baris.
agc
Ya, skrip saya tidak mempertimbangkan pohon ketergantungan lengkap. Anda dapat mencoba menyesuaikannya untuk level hierarki yang lebih banyak.
sealor