Wyświetl listę ręcznie instalowanych pakietów najwyższego poziomu bez ich zależności


12

Istnieje wiele sposobów wyświetlania pakietów instalowanych ręcznie apt, na przykład:

apt-mark showmanual

Ale czasami ta wydajność jest zbyt duża. Na przykład, jeśli użytkownik ręcznie zainstalował pakiet foo:

apt-get install foo

... i foood tego zależało bari baz, wtedy apt-mark showmanualbyłoby wyjście:

bar
baz
foo

Jak możemy wyświetlić listę ręcznie zainstalowanych pakietów najwyższego poziomu ( tj. foo ) Bez ich zależności ( tj. Nie baz, ani bar)?


Poniższy kod wydaje się działać, ale wywołanie GNU kilkaset razy jest zbyt wolne (trzy godziny z czterordzeniowym procesorem):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

Hmm Odpowiedzi i kod OP są tak różne i zwracają nieco inne dane, że trochę się rozmyślam, które dane metody są najbardziej poprawne. Być może potrzebna jest odpowiedź ankiety, zaczynając od minimalnego systemu testowego i dodając kilka programów na raz, aby zobaczyć, jak i kiedy wyniki różnią się.
agc

Odpowiedzi:


9

Można to zrobić za pomocą API apt Pythona. Pakiety, które widzisz, apt-mark showmanualsą dokładnie tymi, w apt.cache.Cache()których is_installedjest to prawda i is_auto_installedfałsz. Ale łatwiej jest przetwarzać zależności:

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

Nawet ta lista zawiera niektóre pakiety, których nie spodziewałbym się tam zobaczyć ( init, grep?!).


W moim systemie ten kod generuje nadzbiór mojego 3-godzinnego kodu, ale nie pokazuje żadnych niespodzianek takich jak initi grep(może twoje apt dane są uszkodzone?), Również pokazuje zbyt wiele bibliotek. OTOH, mój 3-godzinny kod pomija kilka elementów, które powinny tam być, elementy, które pythondrukuje powyższy kod. Być może brakujące elementy nie zostały zainstalowane apt.
agc,

@agc to prawdopodobnie dlatego, że się nie powtórzyłem. Spróbuję opcji rekurencyjnej po weekendzie. Nawet przy rekursji spodziewałbym się, że będzie to o wiele szybsze niż wielokrotne wywoływanie apt-rdepends
muru

Powyższy pythonkod jest 3600 razy szybszy (tj. Zajął 3 sekundy) niż mój kod (3 godziny). Czekamy na przetestowanie wersji rekurencyjnej ...
agc

3

Poniższy skrypt powłoki wyszukuje rodziców wszystkich zainstalowanych zależności.

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

Użyłem tsortw tym skrypcie. Zakładam, że podczas dodawania znacznika na końcu bez zależności znacznik będzie również ostatnim wpisem bez zależności w moim wyniku. Mogę więc odróżnić ostatni pakiet bez zależności od pierwszego pakietu z zależnościami.

Zauważyłem jeden problem z tym rozwiązaniem:
na wykresie zależności występują cykle. Te wpisy są ignorowane przez tsort.


2

Wszystkie ręcznie zainstalowane pakiety bez ich pierwszego poziomu zależności można znaleźć w następujący sposób:

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

Możesz także użyć następującej magii jedno-liniowej:

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)

O wiele szybciej. Wyprowadza to, co jest przeważnie nadzbiorem kodu OP, ale brakuje też kilku, takich jak dasherpakiet. W moim systemie kod OP przepływał przez sort -Vwyjścia 475 linii, kod Muru wyprowadza 914 linii (włącznie dasher), a kod odpowiedzi odpowiada 995 linii.
agc

Tak, mój skrypt nie uwzględnia pełnego drzewa zależności. Możesz spróbować dostosować go do większej liczby poziomów hierarchii.
sealor
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.