Elencare i pacchetti installati manualmente di livello superiore senza le relative dipendenze


12

Esistono molti modi per mostrare i pacchetti installati manualmente utilizzando apt, ad esempio:

apt-mark showmanual

Ma a volte quell'output è troppo. Ad esempio se l'utente ha installato manualmente il pacchetto foo:

apt-get install foo

... e foodipendeva da bare baz, quindi, apt-mark showmanualavrebbe prodotto:

bar
baz
foo

Come possiamo elencare solo i pacchetti di livello superiore installati manualmente ( cioè foo ) senza le loro dipendenze ( cioè no baz, né bar)?


Il seguente codice sembra funzionare, ma GNU che parallel chiama apt-rdependsalcune centinaia di volte è troppo lento (tre ore con una CPU a 4 core):

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

Hmm. Le risposte e il codice OP sono tutti così diversi e restituiscono dati leggermente diversi, che sto diventando un po 'confuso su quali dati del metodo siano i più corretti. Forse è necessaria una risposta al sondaggio, a partire da un sistema di test minimo, e aggiungendo alcuni programmi alla volta per vedere come e quando l'output varia.
agc,

Risposte:


9

Questo potrebbe essere fatto usando l'API apt Python. I pacchetti che vedi apt-mark showmanualsono esattamente quelli in apt.cache.Cache()cui is_installedè vero ed is_auto_installedè falso. Tuttavia, è più semplice elaborare le dipendenze:

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

Anche questo elenca alcuni pacchetti che non mi aspetterei di vedere lì ( init, grep?!).


Sul mio sistema quel codice genera un superset del mio codice di 3 ore, ma non mostra sorprese come inite grep(forse i tuoi dati apt sono corrotti?), Inoltre mostra troppe librerie. OTOH, il mio codice di 3 ore manca alcuni elementi che dovrebbero essere lì, elementi che le suddette pythonstampe di codice. Forse gli elementi mancanti non sono stati installati con apt.
agc,

@agc probabilmente è perché non ho fatto ricorso. Proverò un'opzione ricorsiva dopo il fine settimana. Anche con la ricorsione, però, mi aspetto che questo sia molto più veloce di chiamare ripetutamente apt-rdepends
muru,

Il pythoncodice sopra è 3600 volte più veloce (cioè ci sono voluti 3 secondi) rispetto al mio codice (3 ore). In attesa di testare la versione ricorsiva ...
agc,

3

Il seguente script di shell cerca i genitori di tutte le dipendenze installate.

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

Ho usato tsortin questo script. Presumo che quando si aggiunge un marcatore alla fine senza dipendenze, il marcatore sarà anche l'ultima voce senza dipendenze nel mio risultato. Quindi posso differenziare tra l'ultimo pacchetto senza dipendenze e il primo pacchetto con dipendenze.

Ho notato un problema con questa soluzione:
ci sono cicli nel grafico delle dipendenze. Queste voci sono ignorate da tsort.


2

Puoi trovare tutti i pacchetti installati manualmente senza il loro primo livello di dipendenze come segue:

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

Puoi anche usare la seguente magia da una fodera:

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)

Più veloce. Questo produce principalmente un superset del codice OP, ma ne manca anche alcuni, come il dasherpacchetto. Sul mio sistema il codice OP convogliata attraverso sort -Vle uscite 475 linee, di Muru codice uscite 914 linee, (compresi dasher), e le uscite di codice di questa risposta 995 linee.
agc,

Sì, il mio script non considera l'albero delle dipendenze completo. Potresti provare ad adattarlo per più livelli gerarchici.
Sigillo il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.