MC & Ptółta Pełta, 16:39 piątek, 27.01.2017 r.
Ilustracja do artykułu: Linux/Ubuntu - Jak wypisać wszystkie zainstalowane pakiety

Linux/Ubuntu - Jak wypisać wszystkie zainstalowane pakiety

Artykuł ten ma na celu przedstawienie sposobów wylistowania wszystkich zainstalowanych pakietów w systemie Linux/Ubuntu. Rozróżnimy przy tym pakiety zainstalowane jawnie, jak i te, które były dla tych jawnych tylko zależnościami. Sprawdzimy różne podejścia do problemu, a także spróbujemy tę umiejętność wykorzystać praktycznie, tworząc listę zainstalowanych programów, a następnie przenosząc ją na inną maszynę, w celu odtworzenia oprogramowania.

Wypiszmy wszystkie pakiety w systemie

Zaczniemy od rzeczy prostszej, to jest od uzyskania listy wszystkich pakietów obecnych w systemie, niezależnie od tego, czy były instalowane ręcznie, czy tylko zostały pobrane automatycznie w ramach spełniania zależności. Lista taka może być przydatna do nieco głębszej analizy tego co w systemie siedzi, ale nie ma też co ukrywać, że do innych celów może okazać się zupełnie niewygodna. Po prostu szum informacyjny w postaci zbyt dużej liczby elementów takiej listy pakietów może nam zaciemnić obraz i utrudnić, jeśli nie uniemożliwić w ogóle, znalezienie tego co nas w danej sytuacji interesuje. Niemniej jednak zacznijmy od listy wszystkich pakietów, a w dalszej części artykułu zawęzimy poszukiwania.

Ścieżek do uzyskania listy wszystkich pakietów w systemie jest wiele. Ja chciałbym przedstawić tutaj pięć z nich, choć z całą pewnością, nie są to jedyne podejścia. W pierwszym przypadku wykorzystamy pliki systemowe, dwa kolejne zaś oprzemy na menedżerze pakietów dpkg, a przedostatni sposób będzie dedykowany wyłącznie wersjom systemu Ubuntu od 14.04 w górę. Na samym końcu wspomnimy o użytkownikach programu aptitude.

Analiza plików systemowych

Zacznijmy więc od podejrzenia pliku systemowego /var/lib/apt/extended_states. Uważam, że jest to jeden z mniej wygodnych sposobów, ponieważ należy zapamiętać ścieżkę do pliku, niemniej jednak warto o nim wspomnieć. Najpierw z czystej ciekawości, sprawdźmy ile wierszy liczy sobie ten plik.

$ cat /var/lib/apt/extended_states | wc -l
8744

Blisko 8800 wpisów, czyli całkiem sporo. Wyświetlmy sobie więc tylko kilka pierwszych linijek co powinno pozwolić nam zrozumieć strukturę tego pliku.

$ cat /var/lib/apt/extended_states | head
Package: dvd+rw-tools
Architecture: amd64
Auto-Installed: 1

Package: grub-gfxpayload-lists
Architecture: amd64
Auto-Installed: 0

Package: unity-control-center-signon
Architecture: amd64

Na pierwszy rzut oka możemy stwierdzić, że na każdy pakiet przypadają trzy linijki opisowe i jedna odstępu. Pamiętając liczbę wierszy pliku możemy szacować, że w systemie jest niecałe 2200 pakietów. Przyglądając się dalej outputowi, widzimy, że pierwsza linijka opisu zawiera nazwę pakietu, druga architekturę, zaś trzecia... może być nieco enigmatyczna. Otóż własność "Auto-Installed" o wartości 0 mówi nam o tym, że pakiet został zainstalowany ręcznie (siłą rzeczy, wartość 1 oznacza, że pakiet został pobrany automatycznie jako zależność). To cenna informacja, którą spróbujemy wykorzystać w dalszej części artykułu.

Dpkg po raz pierwszy

Czas wziąć pod lupę menedżera pakietów dpkg. Przeglądając dokumentację, szybko da się zauważyć coś, czego intuicyjnie powinniśmy się spodziewać, a mianowicie flagę, która określi naszą potrzebę wylistowania pakietów. Ma ona popularną postać --list, bądź w skróconym zapisie -l. Jeśli zajrzymy głębiej do dokumentacji, to dowiemy się, że komenda ta wylistuje nam pakiety pochodzące z pliku /var/lib/dpkg/status tylko w nieco bardziej opracowanej formie, będącej bardziej czytelną. Podobnie jak wcześniej zacznijmy od sprawdzenia liczby zwracanych rekordów.

$ dpkg --list | wc -l
2921

No i ciekawostka. Kłopotliwej różnicy w liczbie pakietów jaką szacowaliśmy w poprzednim rozdziale nie sposób przemilczeć. Nim jednak zastanowimy się, skąd ta różnica pochodzi, sprawdźmy jak wygląda struktura outputu komendy.

$ dpkg --list | head
Wybór:U=nieznany/I=instalacja/R=usunięcie/P=wyczyszczenie/H=zatrzymanie | Stan:N=brak/I=zainstalowany/C=skonfigurowany/U=rozpakowany/ |/ F=częśc. skonfigurowany/H=częśc. zainstalowany/W=wyzw. czek./T=wyzw. zapl. || Błędy?=(brak)/R-do pon. inst. (duże litery w "Stan" i "Błędy"=problemy) ||/ Nazwa Wersja Architektura Opis +++-=====================================================-===================================================-============-=============================================================================== rc 7kaa 2.14.4-1 amd64 Seven Kingdoms Ancient Adversaries: real-time strategy game ii account-plugin-aim 3.8.6-0ubuntu9.2 amd64 Messaging account plugin for AIM ii account-plugin-facebook 0.11+14.04.20140409.1-0ubuntu2 all GNOME Control Center account plugin for single signon - facebook ii account-plugin-flickr 0.11+14.04.20140409.1-0ubuntu2 all GNOME Control Center account plugin for single signon - flickr

Ciężko silić się na opisy czegoś, co jest bardzo dobrze opatrzone tytułami i legendą, powiem więc tylko, że informacje o pakietach mamy wypisane w kolejnych wierszach z podziałem na kolumny. Forma taka jest wygodna do przeglądania, ale mniej jeśli chodzi o filtrowanie wyników w dalszych operacjach. Warto jednak wiedzieć o tej możliwości skorzystania z dpkg.

Wróćmy jednak do problematycznej liczby pakietów, jaką uzyskaliśmy w tej operacji. Oczywiście widzimy, że kilka dodatkowych wierszy niepotrzebnie zliczonych stanowi legenda i opis tabeli, będącej rezultatem, jednak różnica w liczbie pakietów jest wyraźnie większa. Próbując dojść przyczyn, spójrzmy na poniższe polecenia i ich rezultaty.

$ cat /var/lib/apt/extended_states | grep "libpython3.4"
Package: libpython3.4

$ dpkg --list | grep "libpython3.4"
ii  libpython3.4:amd64                                    3.4.3-1ubuntu1~14.04.5                              amd64        Shared Python runtime library (version 3.4)
ii  libpython3.4-minimal:amd64                            3.4.3-1ubuntu1~14.04.5                              amd64        Minimal subset of the Python language (version 3.4)
ii  libpython3.4-stdlib:amd64                             3.4.3-1ubuntu1~14.04.5                              amd64        Interactive high-level object-oriented language (standard library, version 3.4)

Przefiltrowaliśmy wyniki dwóch poruszonych rozwiązań i widzimy, że o ile w pierwszym z nich znajduje tylko jeden pakiet o nazwie libpython3.4, o tyle w przypadku drugiego mamy 3 takie pakiety. Wnioskować stąd należy, że rezultat wylistowania pakietów przez dpkg jest bardziej szczegółowy, natomiast można również przypuszczać, że pakiety w pliku /var/lib/apt/extended_states bywają pogrupowane w swoich sekcjach. Myślę, że to może być główna różnica, której warto być świadomym. O drugiej dowiemy się w kolejnym rozdziale.

Dpkg po raz drugi i... nieostatni

Menedżer pakietów dpkg daje nam jeszcze jedną możliwość uzyskania listy pakietów i będzie to możliwość najbardziej interesująca nas z punktu widzenia praktycznego aspektu problemu, jaki został zarysowany we wstępie, czyli odtworzenia oprogramowania z jednego komputera na drugi. Do tego celu posłużymy się flagą --get-selections. Trzymając się konwencji przyjętej w tym artykule, sprawdźmy liczbę zwracanych rezultatów.

$ dpkg --get-selections | wc -l
2915

Tym razem bez niespodzianek. Biorąc pod uwagę fakt, że w poprzednim podejściu 6 pierwszych linijek stanowiła preambuła, liczba pakietów pozostaje taka sama. Nie mając się do czego przeczepić, zajrzyjmy do tego jak wygląda output.

$ dpkg --get-selections | head
7kaa						deinstall
account-plugin-aim				install
account-plugin-facebook				install
account-plugin-flickr				install
account-plugin-google				install
account-plugin-jabber				install
account-plugin-salut				install
account-plugin-twitter				install
account-plugin-windows-live			deinstall
account-plugin-yahoo				install            
        

Widzimy że rezultat stanowią dwie kolumny: nazwa pakietu i jego status. Zapowiedziałem również, że w tym przypadku zauważymy drugi przyczynek do różnicy w liczbie pakietów jakiej doświadczyliśmy uprzednio. Część z pakietów ma status deinstall, czyli są przeznaczone do usunięcia i nie znajdują się one na liście prezentowanej w pliku extended_states.

$ cat /var/lib/apt/extended_states | grep "account-plugin-windows-live"
$

Zerknijmy jeszcze, ile takich pakietów o statusie deinstall jest obecnych na liście.

$ dpkg --get-selections | grep "deinstall" | wc -l
206

Zdaje się, że mamy dość dobre wyjaśnienie dla zagadki z liczbą pakietów.

Do metody z tego rozdziału jeszcze wrócimy, gdy zajmiemy się możliwością odtworzenia oprogramowania na innej maszynie, gdyż do tego celu służy ona najlepiej.

Podejście dostępne od Ubuntu 14.04

Póki co jednak wspomnijmy choć o rozwiązaniu, jakie dostępne jest systemom Ubuntu od wersji 14.04 w górę. Możemy na nich odwołać się bezpośrednio do apt, bowiem posiada on opcję list. Równie istotna jest również dodatkowa flaga --installed, jaką należy przekazać, aby wyniki ograniczyć wyłącznie do pakietów zainstalowanych, a nie w ogóle dostępnych na repozytoriach. Podliczmy wyniki.

$ apt list --installed | wc -l

WARNING: apt does not have a stable CLI interface yet. Use with caution in scripts.

2593

Widzimy, że poza warningiem po raz kolejny mamy rozbieżność w wynikach. Zerknijmy jak wyglądają.

$ apt list --installed | head
 WARNING: apt does not have a stable CLI interface yet. Use with caution in scripts.

        
 Listing...
        
 account-plugin-aim/trusty-updates,now 3.8.6-0ubuntu9.2 amd64 [installed,automatic]
 account-plugin-facebook/trusty-updates,now 0.11+14.04.20140409.1-0ubuntu2 all [installed,automatic]
 account-plugin-flickr/trusty-updates,now 0.11+14.04.20140409.1-0ubuntu2 all [installed,automatic]
 account-plugin-google/trusty-updates,now 0.11+14.04.20140409.1-0ubuntu2 all [installed,automatic]
 account-plugin-jabber/trusty-updates,now 3.8.6-0ubuntu9.2 amd64 [installed,automatic]
 account-plugin-salut/trusty-updates,now 3.8.6-0ubuntu9.2 amd64 [installed,automatic]
 account-plugin-twitter/trusty-updates,now 0.11+14.04.20140409.1-0ubuntu2 all [installed,automatic]
 account-plugin-yahoo/trusty-updates,now 3.8.6-0ubuntu9.2 amd64 [installed,automatic] 
 accountsservice/trusty-updates,now 0.6.35-0ubuntu7.3 amd64 [installed,automatic]
 

Widzimy, że wyniki mają postać kolejno wypisanych informacji: nazwy pakietu, dystrybucji, wersji, architektury oraz statusu, który wskazuje między innymi na to, czy pakiet został zainstalowany automatycznie, czy jawnie przez administratora, co będzie dla nas szczególnie interesujące w kolejnym rozdziale.

Coś dla użytkowników aptitude

Użytkownicy stosujący aptitude jako menedżera pakietów, również mogą wypisać wszystkie zainstalowane pakiety, z tą różnicą, że w tym wypadku należy skorzystać z opcji search opatrzonej odpowiednim wzorcem.

$ aptitude search '~i' | head
i A account-plugin-aim              - Messaging account plugin for AIM          
i A account-plugin-facebook         - GNOME Control Center account plugin for si
i A account-plugin-flickr           - GNOME Control Center account plugin for si
i A account-plugin-google           - GNOME Control Center account plugin for si
i A account-plugin-jabber           - Messaging account plugin for Jabber/XMPP  
i A account-plugin-salut            - Messaging account plugin for Local XMPP (S
i A account-plugin-twitter          - GNOME Control Center account plugin for si
i A account-plugin-yahoo            - Messaging account plugin for Yahoo!       
i A accountsservice                 - Wyszukiwanie i zarządzanie informacjami o 
i A acl                             - Narzędzia list kontroli dostępu (ACL)
        

W ten sposób poprosiliśmy o wypisanie wyłącznie zainstalowanych pakietów. Format wyników jest kolumnowy: stan pakietu, czy zainstalowany automatycznie, czy manualnie, nazwa i opis.

Pokażmy tylko pakiety zainstalowane ręcznie

Spróbujemy teraz wyłuskać z listingów wcześniej pokazanych, tylko te pakiety, które zostały zainstalowane explicite.

Filtrujemy wcześniejsze wyniki

Jak pamiętamy, struktura wpisu dotyczącego jednego pakietu w pliku /var/lib/apt/extended_states rozciągała się na 3 linijki, zaś te zainstalowane jawnie oznaczone były wartością 0 dla własności Auto-Installed. Poniższy ciąg poleceń pozwala nam wybrać najpierw tylko te rekordy, które nie są zainstalowane automatycznie, następnie wyciągamy z nich tylko jedną linijkę, zawierającą nazwę pakietu i do celów prezentacji ograniczamy liczbę wyników do pierwszych dziesięciu.

$ cat /var/lib/apt/extended_states | sed -e '/Package: .*/,/Auto-Installed: 0/!d' | grep "^Package: .*$" | head
Package: dvd+rw-tools
Package: grub-gfxpayload-lists
Package: unity-control-center-signon
Package: bind9-host
Package: growisofs
Package: zenity
Package: python3-pyatspi
Package: dc
Package: python3-pyparsing
Package: libgoa-1.0-0b

Podobną taktykę filtrowania wyników zastosujemy również w przypadku polecenia `apt list`, tym jednak razem pozostawimy wyniki wyłącznie mające status [installed].

$ apt list --installed | grep "[installed]$" | head

WARNING: apt does not have a stable CLI interface yet. Use with caution in scripts.

acpi-support/trusty,now 0.142 amd64 [installed]
activity-log-manager-control-center/trusty-updates,now 0.9.7-0ubuntu14.1 all [installed]
adduser/trusty,now 3.113+nmu3ubuntu3 all [installed]
aisleriot/trusty,now 1:3.10.2-1 amd64 [installed]
alsa-base/trusty,now 1.0.25+dfsg-0ubuntu4 all [installed]
anacron/trusty,now 2.3-20ubuntu1 amd64 [installed]
apache2/trusty-updates,trusty-security,now 2.4.7-1ubuntu4.13 amd64 [installed]
app-install-data-partner/trusty,now 13.04 all [installed]
apt/trusty-updates,trusty-security,now 1.0.1ubuntu2.17 amd64 [installed]
apt-transport-https/trusty-updates,trusty-security,now 1.0.1ubuntu2.17 amd64 [installed]

Warto również pokazać, jak uzyskać podobny rezultat przy pomocy wspominanego aptitude. Ponownie wykorzystamy opcję search, tylko w zadanym wzorcu zawęzimy zakres poszukiwań, do pakietów zainstalowanych manualnie, czemu odpowiada poniższa komenda.

$ aptitude search '~i!~M' | head
i   acpi-support                    - Skrypty obsługujące wiele zdarzeń ACPI    
i   activity-log-manager-control-ce - blacklist configuration for Zeitgeist (tra
i   adduser                         - Dodawanie i usuwanie użytkowników oraz gru
i   aisleriot                       - Kolekcja gier karcianych, pasjansów, do GN
i   alsa-base                       - Pliki konfiguracyjne sterownika ALSA      
i   anacron                         - Program podobny do crona, uwzględniający p
i   apache2                         - Apache HTTP Server                        
i   app-install-data-partner        - Instalator aplikacji (pliki z danymi dla p
i   apparmor                        - user-space parser utility for AppArmor    
i   apt                             - Menedżer pakietów do wiersza poleceń

Czas na praktykę - przenieśmy oprogramowanie na inny komputer

Po tym dość obszernym przestawieniu możliwości uzyskania listy pakietów, spróbujmy stworzyć taką listę, by następnie odtworzyć zestaw oprogramowania na innej maszynie. Podczas omawiania programu dpkg, wspomnieliśmy, że jego wywołanie z flagą --get-selections nada się doskonale do tego celu. Wszystko to za sprawą tego, że dpkg po prostu przewiduje możliwość odtworzenia takiego wcześniej przygotowanego backupu w postaci listy pakietów. Zacznijmy od przygotowania jej we właściwy i znany nam już sposób.

$dpkg --get-selections > listaPakietow

Przekierowujemy wyniki do pliku listaPakietow, który stanowi nasz backup. Całość problemu sprowadza się teraz jedynie do przeniesienia tego pliku oraz zaaplikowania go w systemie. Aplikację tę należy rozłożyć na dwa etapy: wyczyszczenia istniejących informacji o pakietach oraz odtworzenia nowych z pliku, czemu odpowiadają dwa kolejne polecenia.

$dpkg --clear-selections
$dpkg --set-selections < listaPakietow

Oczywiście same informacje o pakietach to nie wszystko, należy je jeszcze pobrać i zainstalować. Można to zrobić np. takim wywołaniem.

$ sudo apt-get dselect-upgrade

Zakończenie

Myślę, że dość szerokim spojrzeniem udało się objąć temat listowania pakietów. Na pewno nie wyczerpałem go zupełnie, bo można choćby jeszcze bliżej zbadać różnice między poszczególnymi podejściami, jakie zaprezentowałem. Liczę jednak, że to, co nie zostało powiedziane w artykule, padnie w dyskusji w komentarzach, do której zachęcam.

Komentarze (4)

Imię:
Treść:
Administrator 2019-01-15 07:38:47
@czesio, o Twoim sposobie pisałem w rozdziale "Podejście dostępne od Ubuntu 14.04". Polecam zajrzeć, bo pokazuję tam, że istnieje flaga pozwalająca odfiltrować zainstalowane pakiety, więc nie trzeba używać grepa.
czesio 2018-12-28 11:05:47
ja to robie prosciej apt list | grep installed | more
Administrator 2018-01-21 12:50:38
@heng, cieszę się, że artykuł mógł pomóc.
heng 2018-01-19 19:59:25
dziekuje bardzo. Tego szukalem :)