Como faço para listar comandos que um pacote fornece? [duplicado]

12

Estou curioso sobre o que um determinado pacote fornece ao meu sistema. Por comando, quero dizer um executável no caminho que eu posso executar a partir da linha de comando ( ls , grep , sed , etc).

Não estou tentando descobrir o pacote a partir do comando, o que pode ser feito com:

dpkg -S 'which command'

Eu quero o oposto, uma lista de comandos de um pacote.

    
por Oli 19.03.2014 / 11:35

4 respostas

7

O pequeno loop a seguir lidará com isso com pacotes instalados .

$ for f in $(dpkg -L login); do [[ $(type -P "${f##*/}") == "$f" ]] && echo ${f##*/}; done
nologin
lastlog
newgrp
faillog
su
login
sg

Como funciona:

  • dpkg -L package gera uma lista de todos os arquivos em um pacote pelo qual nós iteramos.
  • Retiramos o nome do diretório com um pouco de conhecimento básico: ${f##*/} e
  • Usando o bash-builtin type -P command , vemos se esse comando está no caminho e que seu caminho é igual ao arquivo com o qual começamos.
  • Terminamos enviando o comando abreviado.
  • [[ condition ]] && command é apenas uma abreviação de uma declaração if..then.

É importante notar que nem todos os pacotes contêm os comandos esperados. O Apache é dividido em vários pacotes (com -common e -bin subpackages) e o comando vlc não está no pacote vlc , está em vlc-nox . Existem muitos exemplos como esse.

Isso pode ser adaptado por idéia de Gilles , fazendo uma correspondência de string em vez de realmente verificar, mas mantendo tudo em um processo bash (e ainda usando o caminho todo ).

for f in $(dpkg -L login); do [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/}; done

A principal diferença aqui é o [[$f =~ ^${PATH//:/|} ]] . Essa é uma pesquisa regex em Bash. A parte ${PATH//:/|} está pegando o conteúdo de $ PATH e os está cortando em um pequeno regex sujo. A condição deve verificar se a string começa com parte do caminho.

    
por Oli 19.03.2014 / 11:35
3

Relacione os arquivos do pacote que estão em um diretório no PATH. Você só precisa considerar o PATH padrão, não as customizações do usuário, já que os pacotes usam apenas diretórios padrão.

dpkg -L PACKAGE-NAME… | sed -n 's!^\(/s\?bin\|/usr/s\?bin\|/usr/games\)/!!p' | sort

Remova as s\? partes se você quiser apenas os programas destinados a usuários comuns sem sudo .

Se o pacote não estiver instalado, substitua dpkg -L por apt-file -F list .

Isso erra alguns programas porque eles são fornecidos através de alternativas . Por exemplo, para o pacote ftp , apenas netkit-ftp e pftp são fornecidos, mas esse pacote realmente fornece o comando ftp , porque /usr/bin/ftp é um link simbólico para /etc/alternatives/ftp , que é um link simbólico para uma das implementações ftp no sistema, potencialmente /usr/bin/netkit-ftp . O seguinte comando (que não é um exemplo de boa programação, apenas um grande one-liner) lista os comandos fornecidos por um pacote através do mecanismo de alternativas, como atualmente configurado.

perl -lwe 'foreach ('dpkg -L @ARGV') {chomp; ++$p{$_}} foreach (</bin/* /sbin/* /usr/bin/* /usr/sbin/*>) {$e = readlink; next unless defined $e and $e =~ m!^/etc/alternatives/!; $t = readlink $e; print if $p{$t}}' PACKAGE_NAME…

Se você quiser listar os comandos que podem ser fornecidos por meio de uma alternativa que está atualmente configurada para apontar para um pacote diferente, será necessário analisar os arquivos em /var/lib/dpkg/alternatives .

Links simbólicos e arquivos de configuração que implementam os mecanismos de alternativas não são registrados em pacotes, mas registrados automaticamente em postinst , o que torna difícil (e tecnicamente impossível se o script de instalação de um pacote não seguir convenções) para consultar alternativas fornecidas por um pacote desinstalado.

    
por Gilles 19.03.2014 / 12:59
1

Minha outra resposta é bastante certa, mas funciona apenas para pacotes instalados. Aqui está um crack em uma versão que funciona para pacotes ainda não instalados (mas aqueles que estão disponíveis apenas nos repositórios principais)

export PACKAGE="login"; source /etc/lsb-release; source <(dpkg-architecture); for f in $(wget -qO- "http://packages.ubuntu.com/$DISTRIB_CODENAME/$DEB_BUILD_ARCH/$PACKAGE/filelist" | sed -n '1,/<pre>/d;/<\/pre>/,$d;p'); do [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/}; done

É horrivelmente mais complicado, por isso vou escrever uma versão detalhada:

export PACKAGE="login";
source /etc/lsb-release;
source <(dpkg-architecture);

URL="http://packages.ubuntu.com/$DISTRIB_CODENAME/$DEB_BUILD_ARCH/$PACKAGE/filelist"

# We grab the packages.ubuntu.com version of the file list (and strip it with sed)
for f in $(wget -qO- "$URL" | sed -n '1,/<pre>/d;/<\/pre>/,$d;p'); do

    # We then compare every file provided in the package with every path stub
    [[ $f =~ ^${PATH//:/|} ]] && echo ${f##*/};
done
    
por Oli 19.03.2014 / 13:08
0

Um método mais fácil é apenas consultar a web:

release=$(lsb_release -sc)
arch=$(uname -m)
package=$@

for i in $package; do
   printf "List of files in $i package"
   curl http://packages.ubuntu.com/$release/$arch/$i/filelist 2>/dev/null | grep -oP '/[\w\d/.]+$
done

Isso tem a vantagem de você precisar apenas de curl e sed (o que o sistema Ubuntu não tem) e você pode alterá-lo com wget facilmente, se necessário. Ele consulta vários pacotes com um único comando, o que é uma vantagem.

Qualquer equivalente com outra linguagem de programação + analisador html deve funcionar melhor e menos provável de quebrar se algo mudar na lista de pacotes.

Alterando o host, você também pode consultar o banco de dados Debian.

    
por Braiam 19.03.2014 / 15:46