Listar pacotes em um sistema baseado em apt pela data de instalação

104

Como posso listar pacotes instalados por data de instalação?

Eu preciso fazer isso no debian / ubuntu. As respostas para outras distribuições também seriam boas.

Instalei muitas coisas para compilar um determinado pedaço de código e quero obter uma lista dos pacotes que tive que instalar.

Elazar Leibovich
fonte
1
Eu estava pesquisando no Google por "data de lançamento do apt" sem sorte, talvez esse comentário ajude futuros googlers.
ThorSummoner
Pergunta semelhante no askubuntu.com "Como listar todos os pacotes instalados" .
JamesThomasMoon1979

Respostas:

66

Distribuições baseadas em RPM como Red Hat são fáceis:

rpm -qa --last

No Debian e em outras distribuições baseadas em dpkg, seu problema específico também é fácil:

grep install /var/log/dpkg.log

A menos que o arquivo de log tenha sido girado, nesse caso, você deve tentar:

grep install /var/log/dpkg.log /var/log/dpkg.log.1

Em geral, dpkge aptnão parecem rastrear a data da instalação, passando pela falta de tal campo na dpkg-querypágina de manual.

E, eventualmente, os /var/log/dpkg.log.*arquivos antigos serão excluídos pela rotação do log, para que não seja garantido que você tenha todo o histórico do seu sistema.

Uma sugestão que aparece algumas vezes (por exemplo, esta discussão ) é olhar para o /var/lib/dpkg/infodiretório. Os arquivos sugerem que você tente algo como:

ls -t /var/lib/dpkg/info/*.list | sed -e 's/\.list$//' | head -n 50

Para responder sua pergunta sobre seleções, aqui está uma primeira passagem.

construir lista de pacotes por datas

$ find /var/lib/dpkg/info -name "*.list" -exec stat -c $'%n\t%y' {} \; | \
    sed -e 's,/var/lib/dpkg/info/,,' -e 's,\.list\t,\t,' | \
    sort > ~/dpkglist.dates

construir lista de pacotes instalados

$ dpkg --get-selections | sed -ne '/\tinstall$/{s/[[:space:]].*//;p}' | \
    sort > ~/dpkglist.selections

junte-se às 2 listas

$ join -1 1 -2 1 -t $'\t' ~/dpkglist.selections ~/dpkglist.dates \
    > ~/dpkglist.selectiondates

Por alguma razão, não está imprimindo muitas diferenças para mim; portanto, pode haver um erro ou uma suposição inválida sobre o que --get-selectionssignifica.

Obviamente, você pode limitar os pacotes usando find . -mtime -<days>ou head -n <lines>e alterar o formato de saída como desejar, por exemplo

$ find /var/lib/dpkg/info -name "*.list" -mtime -4 | \
    sed -e 's,/var/lib/dpkg/info/,,' -e 's,\.list$,,' | \
    sort > ~/dpkglist.recent

$ join -1 1 -2 1 -t $'\t' ~/dpkglist.selections ~/dpkglist.recent \
    > ~/dpkglist.recentselections

para listar apenas as seleções que foram instaladas (alteradas?) nos últimos 4 dias.

Você provavelmente também pode remover os sortcomandos depois de verificar a ordem de classificação usada dpkg --get-selectionse tornar o findcomando mais eficiente.

Mikel
fonte
8
Eu normalmente gosto apt-getmais do que rpm, mas agora o debian recebe -1 por não salvar a data de instalação no banco de dados. O truque debian inclui todos os pacotes instalados, não apenas os pacotes selecionados , mas é um bom começo.
Elazar Leibovich
Para o Debian você obtém menos sujeira (remove half-installedentradas) se o fizer:grep install\ /var/log/dpkg.log
Pierz
@ Mikel - Ótima resposta. Eu expandi o arquivo 'gather /var/lib/dpkg/info/*.list file' e adicionei o código para filtrar todos, exceto os "pacotes de nível superior" (pacotes atp dos quais nenhum outro pacote atp depende). Esse post < askubuntu.com/a/948532/723997> responde à pergunta "Como posso ver o histórico dos comandos de instalação do apt-get que executei manualmente? ".
Craig Hicks
1
Debian / Ubuntu: grep " install " /var/log/dpkg.loglista apenas as linhas de "instalação" em vez de mostrar as linhas de "status" também.
dessert
Se nem o apt nem o dpkg store instalam / modificam a data e hora, isso me parece inaceitável em 2019. Contamos com arquivos de log grepping que ainda podem ou não estar na máquina? Como é esse o caso?
theferrit32 14/02
20

Mikel mostrou como fazer isso no nível do dpkg . Em particular, /var/lib/dpkg/info/$packagename.listé criado quando o pacote é instalado (e não é modificado posteriormente).

Se você usou as ferramentas do APT (o que você presumivelmente usou desde que se preocupa com pacotes instalados automaticamente ou manualmente), há um histórico /var/log/apt/history.log. Desde que não tenha girado, ele acompanha todas as instalações, atualizações e remoções do APT, com uma anotação para pacotes marcados como instalados automaticamente. Este é um recurso relativamente recente, introduzido no APT 0.7.26, portanto, no Debian, ele apareceu no squeeze. No Ubuntu, o 10.04 possui, history.logmas a anotação instalada automaticamente não está presente até a 10.10.

Gilles
fonte
1
Como Mikel apontou: "E, eventualmente, os arquivos /var/log/dpkg.log.* serão excluídos pela rotação do log, de modo que não será garantido que você tenha todo o histórico do seu sistema.". Veja este < askubuntu.com/a/948532/723997 resposta> para saber como detectar os pacotes de nível superior atual (ou seja, aqueles em que nenhum outro pacote depende)
Craig Hicks
5

Áspero, mas funciona:

for fillo in `ls -tr /var/lib/dpkg/info/*.list` ; 
    do basename ${fillo} | sed 's/.list$//g' ; 
done > forens.txt

ls -ltr /var/lib/dpkg/info/*.list > forentime.txt

for lint in `cat forens.txt` ; do 
    echo -n "[ ${lint} Installed ] : " ; 
    echo -n "`grep /${lint}.list forentime.txt | awk '{ print $6, $7, $8 }'` : " ; 
    ( ( grep -A3 " ${lint}$" /var/lib/apt/extended_states | \
        grep '^Auto' > /dev/null ) && echo "Auto" ) || echo "Manual" ; 
done > pkgdatetime.txt
Dulantha
fonte
2
Boo, silvo por analisar a saída de ls. Veja mywiki.wooledge.org/ParsingLs para obter notas sobre por que isso é perigoso / inerentemente incorreto - a opção mais segura é usar um find -printfou stat --formatgerar um fluxo que possa ser analisado sem ambiguidades.
Charles Duffy
@CharlesDuffy Bom link, mas com o objetivo de simplicidade, o uso ls -al --time-style=long-isodeve ser útil. Além disso, provavelmente é inédito que alguém nomearia um pacote APT \n\t\r\vem seu nome.
precisa saber é o seguinte
4

O /var/log/apt/history.logarquivo tem um formato estranho IMHO.

Data de início: {data} {hora} Linha de comando: {comando} {opções ...} Instalar: {pacote (versão)}, ..., {pacote (versão)}, ... Data final: {data } {Tempo}

Eu teria preferido um registro mais formatado em arquivo de log

{data} {hora} {guia} {pacote} {guia} {versão} {guia} {comando} {opções} \ n

ou algum XML mostrando não apenas um {pacote}, mas qualquer {dependência}.

Conforme implementado atualmente, você pode descobrir as informações que procura, mas isso requer algum processamento forense para extrair os detalhes.

Saint DanBert
fonte
3

Isso funciona para mim em um sistema Debian, acho que o formato do arquivo mudou desde 2011. Esse sistema é bem novo, então eu não esperaria que isso funcionasse em um sistema mais antigo, embora isso possa exigir apenas descompactar os logs e usar um globo para se referir a todos eles.

grep 'install ' /var/log/dpkg.log.1 | sort | cut -f1,2,4 -d' '

Os dois primeiros campos em cada linha do arquivo /var/log/dpkg.logsão a data e a hora. Observe o espaço à direita com a instalação na parte grep, isso ocorre porque as atualizações podem acionar instalações, mas se eu entendi corretamente, você queria saber o que foi instalado pelos usuários.

Amias
fonte
1
Exatamente o que eu faço. Fácil. Mas você pode usar o zgrep e todos os seus logs .gz serão pesquisados ​​como zgrep 'install' /var/log/dpkg.log*. Coloque o espaço antes da palavra "instalar" para evitar aquelas "meia-instalações" traquinas. Eu tive que usar cut -f1,5 para obter o campo de nome do pacote. É claro que, eventualmente, os registros antigos são rotacionados.
geoO
2

Aqui está o one-liner que todos desejam e precisam:

for x in $(ls -1t /var/log/dpkg.log*); do zcat -f $x |tac |grep -e " install " -e " upgrade "; done |awk -F ":a" '{print $1 " :a" $2}' |column -t

O resultado mostrará todos os pacotes (recentemente) instalados e atualizados em ordem cronológica.

A explicação da linha:

  • ls -1t- obtenha todos dpkg.log*os nomes de arquivos em ordem cronológica
  • zcat -f- Se o arquivo for do tipo gzip e descompactá-lo, o ELSE apenas passará o conteúdo.
  • tac- Saída reversa de gato , linha por linha, para garantir que obtemos a ordem cronológica correta.
  • grep- Verifique apenas os pacotes instalados ou de atualização .
  • awk -F ':a'- Separe o campo de arquitetura do nome do pacote
  • column -t - imprima as colunas separadas por espaço

É claro que alguém gostaria de criar um alias para isso, mas infelizmente não é possível, pois o awk depende de aspas simples e duplas. Nesse sentido, é melhor colocar um script bash e onde o :separador é tratado melhor para outras arquiteturas na coluna de campo.

A saída é:

2018-03-06  18:09:47  upgrade  libgomp1                     :armhf  6.3.0-18+rpi1                 6.3.0-18+rpi1+deb9u1
2018-03-05  15:56:23  install  mpg123                       :armhf  <none>                        1.23.8-1
2018-03-05  15:56:23  install  libout123-0                  :armhf  <none>                        1.23.8-1
2018-01-22  17:09:45  install  libmailtools-perl            :all    <none>                        2.18-1
2018-01-22  17:09:44  install  libnet-smtp-ssl-perl         :all    <none>                        1.04-1

Recua:

  • Como mostrado acima, ele funciona apenas na arquitetura ARM e precisa de pequenas modificações no separador de campos da arquitetura
  • Precisa ser colocado em um script para facilitar o alias
  • Não foi testado em outros sistemas * nix
not2qubit
fonte
1

Observando isso porque você menciona que outras respostas de distribuição são bem-vindas. O rpm possui um grande conjunto de tags de formato de saída, um dos quais é INSTALLTIME. (Usando wgetcomo exemplo)

rpm -qi wget --qf "%{NAME},%{INSTALLTIME}\n" | tail -n 1
wget,1454014156

Isso pode ser formatado de algumas maneiras. Eu o uso desta maneira:

rpm -qi wget --qf "%{NAME},%{INSTALLTIME:date}\n" | tail -n 1
wget,Thu 28 Jan 2016 03:49:16 PM EST

Essas duas páginas têm muitas informações excelentes para solucionar problemas de metadados do RPM:

http://www.rpm.org/max-rpm/s1-rpm-query-parts.html

http://www.rpm.org/max-rpm/s1-rpm-query-handy-queries.html

A classificação dessas informações forneceria uma solução funcional para o seu problema.

Jonathan swift
fonte
1

GNU / Linux Debian não possui ferramentas internas para esse problema, mas todas as informações sobre os programas instalados da maneira padrão são salvas em arquivos com o nome do programa.list no local / var / lib / dpkg / info / . Mas não há informações sobre programas instalados manualmente lá.


Uma solução longa e de linha única :

for file_list in `ls -rt /var/lib/dpkg/info/*.list`; do \
    stat_result=$(stat --format=%y "$file_list"); \
    printf "%-50s %s\n" $(basename $file_list .list) "$stat_result"; \
done

Explicação :

  1. ls -rtgera arquivos classificados por modificação de data na ordem inversa, ou seja , com os arquivos mais recentes no final da lista.
  2. stat imprime a data do arquivo em formato legível por humanos.
  3. printf exibe o nome do pacote e a data da sua última modificação.
  4. O forloop como um todo imprime nomes e datas dos pacotes, do mais antigo ao mais recente.

Exemplo de saída (truncado):

.........................................
gnome-system-log                            2016-09-17 16:31:58.000000000 +0300
libyelp0                                    2016-09-17 16:32:00.000000000 +0300
gnome-system-monitor                        2016-09-17 16:32:00.000000000 +0300
yelp-xsl                                    2016-09-17 16:32:01.000000000 +0300
yelp                                        2016-09-17 16:32:03.000000000 +0300
gnome-user-guide                            2016-09-17 16:32:18.000000000 +0300
libapache2-mod-dnssd                        2016-09-17 16:32:19.000000000 +0300
.........................................
linux-compiler-gcc-4.8-x86                  2017-02-26 20:11:02.800756429 +0200
linux-headers-3.16.0-4-amd64                2017-02-26 20:11:10.463446327 +0200
linux-headers-3.16.0-4-common               2017-02-26 20:11:17.414555037 +0200
linux-libc-dev:amd64                        2017-02-26 20:11:21.126184016 +0200
openssl                                     2017-02-26 20:11:22.094098618 +0200
unzip                                       2017-02-26 20:11:23.118013331 +0200
wireless-regdb                              2017-02-26 20:11:23.929949143 +0200
nodejs                                      2017-02-26 20:11:33.321424052 +0200
nasm                                        2017-02-28 16:41:17.013509727 +0200
librecode0:amd64                            2017-03-01 10:38:49.817962640 +0200
libuchardet0                                2017-03-01 10:41:10.860098788 +0200
tree                                        2017-03-04 14:32:12.251787763 +0200
libtar0                                     2017-03-07 09:51:46.609746789 +0200
libtar-dev                                  2017-03-07 09:51:47.129753987 +0200

O principal defeito dessa solução é que ela não é bem testada na produção.

PADYMKO
fonte
Esta é uma solução bonita que faz o trabalho quase pronto. São apenas desvantagens, são que (1) é muito lento e (2) mostra apenas quando um pacote foi atualizado pela última vez , e nenhuma das versões anteriores. Obviamente, isso não é um problema do one-liner, mas como o dpkg não acompanha o histórico /var/lib/dpkg/info/. É também por isso que o uso /var/log/dpkg.log*pode ser preferido.
precisa saber é o seguinte
1

É difícil, mas funciona tão rapidamente quanto outras soluções. O formato da data é aaaammddhhmmss, o que significa que um pouco de remoção ou reordenação e formato resulta em um número que pode ser classificado.

Muito obrigado às outras soluções, esta lista de nomes de pacotes em ordem de instalação que podem ser usados ​​em um sistema operacional criado para criar cópias.

find /var/lib/dpkg/info -name "*.list" -exec stat -c $'%n\t%y' {} \; \
| sed -e 's,/var/lib/dpkg/info/,,' -e 's,\.list\t,\t,' \
| sort | awk '{print $2$3" "$1}' | sed '0,/RE/s/-//' \
| sed '0,/RE/s/-//' | sed '0,/RE/s/://' | sed '0,/RE/s/://' \
| sed '0,/RE/s/\\.//' | sed 's/:armhf//' | sort | awk '{print $2}'
Alexander Cave
fonte
Bem-vindo @ alexander-cave! Adicione algumas linhas de saída para que as pessoas possam ver que tipo de saída esperar.
Not2qubit 5/09