Lista de nível superior instalado manualmente sem suas dependências

6

Existem várias maneiras de mostrar pacotes instalados manualmente usando apt , como:

apt-mark showmanual

Mas às vezes essa saída é demais. Por exemplo, se o usuário instalou manualmente o pacote foo :

apt-get install foo

... e foo dependiam de bar e baz , então apt-mark showmanual produziria:

bar
baz
foo

Como podemos listar apenas os pacotes instalados manualmente de nível superior ( ie foo ) sem suas dependências ( ie não baz , nem bar )?

O código a seguir parece funcionar, mas GNU parallel chamando apt-rdepends algumas centenas de vezes é muito lento (três horas com uma CPU de 4 núcleos):

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
    
por agc 04.06.2017 / 15:58

3 respostas

4

Isso pode ser feito usando a API apt do Python. Os pacotes que você vê em apt-mark showmanual são exatamente aqueles em apt.cache.Cache() para os quais is_installed é verdadeiro e is_auto_installed é falso. Mas é mais fácil processar as dependências:

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

Até mesmo isso lista alguns pacotes que eu não esperaria ver lá ( init , grep ?!).

    
por 07.06.2017 / 08:01
2

Você pode encontrar todos os pacotes instalados manualmente sem o primeiro nível de dependências, como 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

Você também pode usar a seguinte mágica de uma linha:

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)
    
por 11.09.2018 / 21:40
2

O seguinte script de shell procura os pais de todas as dependências instaladas.

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

Eu usei tsort neste script. Eu suponho que ao adicionar um marcador no final sem dependências, o marcador também será a última entrada sem dependências no meu resultado. Então eu posso diferenciar entre o último pacote sem dependências e o primeiro pacote com dependências.

Eu notei um problema com essa solução:
Existem ciclos no gráfico de dependência. Essas entradas são ignoradas por tsort .

    
por 26.09.2018 / 21:49