Как получить список установленных пакетов без зависимостей?

Центр программного обеспечения как-то показывает довольно короткий список установленных пакетов. Как получить это в текстовом файле?

Я старался:

> dpkg --get-selections|wc -l
3265

> aptitude search '~i!~M'|wc -l
1181

> dpkg -l | grep ^ii | sed 's_  _\t_g' | cut -f 2|wc -l
3076

> dpkg --get-selections | grep -v deinstall|wc -l
3076

> apt-mark showmanual|wc -l
1181

Я знаю, что установил несколько десятков пакетов, а не тысячи. Мне нужны в списке именно те пакеты, которые я бы выбрал без зависимостей, чтобы просмотреть их.

ОБНОВИТЬ

Большое спасибо @kos, я наконец получил список с этой командой:

> zcat /var/log/apt/history.log.*.gz | cat - /var/log/apt/history.log | grep -Po '^Commandline: apt-get install \K.*' | tr ' ' '\n' | grep -v '\-\-reinstall'|grep -v '\-\-force-yes'|grep -v '\-y'|grep -v '\-f'|sort|uniq wc -l
103

6 ответов

Решение

Это не дает точного ответа на вопрос: скорее, дает команду перечислить все apt-get install Команды когда-либо выполнялись вместе с некоторыми советами о том, как анализировать список дальше, чтобы получить список всех apt-get install Команды когда-либо выполняются, за исключением тех, что выполняются Ubiquity, поскольку идеального решения этой задачи, похоже, не существует.

zcat /var/log/apt/history.log.*.gz | cat - /var/log/apt/history.log | grep -Po '^Commandline:(?= apt-get)(?=.* install ) \K.*'
  • zcat /var/log/apt/history.log.*.gz: распаковывает все сжатые apt входит в /var/log/apt соединяет их и печатает stdout;
  • cat - /var/log/apt/history.log: добавляет /var/log/apt/history.log и печатает на stdout;
  • grep -Po '^Commandline:(?= apt-get)(?=.* install ) \K.*': выбирает только строки, начинающиеся с Commandline: apt-get содержащий install с начальным и конечным пробелом и печатает остаток от каждой выбранной строки в stdout;

Это выведет список всех apt-get install когда-либо выполняются команды (единственным нежелательным выводом может быть apt-get неопасным install Команда, упоминающая install пакет, но этот пакет не существует (пока?), по крайней мере, в репозиториях по умолчанию);

Примечание. В моей установке (Ubuntu 15.04, 64-битная) первые четыре перечисленные команды - это команды, выполняемые Ubiquity во время установки; чтобы исключить их, вы можете передать вывод sed:

sed '1,4d'

Итак, последняя примерная команда для 64-битной Ubuntu 15.04 будет выглядеть так:

zcat /var/log/apt/history.log.*.gz | cat - /var/log/apt/history.log | grep -Po '^Commandline:(?= apt-get)(?=.* install ) \K.*' | sed '1,4d'
меткий шоу-мануал

предоставит вам список всех установленных вручную пакетов без зависимостей - важно отметить, что он также покажет, какие пакеты были установлены во время установки Ubuntu.

Чтобы записать вывод в файл:

apt-mark showmanual> somefile

На самом деле есть много других способов, таких как использование этой команды

comm -23 <(apt-mark showmanual | sort -u) <(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u) 

Хотя я понятия не имею, как работает выше;)

Для просмотра пакетов, установленных по дате:

Пакеты установлены по дате использования cat /var/log/dpkg.log | grep "\ install\ > somefile"
Пакеты, установленные с помощью dpkg использование ls -l /var/log/dpkg* > somefile - это, вероятно, то, что вы ищете.

Для просмотра пакетов, установленных с помощью dpkg:

Этот файл содержит вышеуказанную информацию: /var/log/dpkg.log

Вот небольшое улучшение принятого ответа, в котором перечислены команды с датами, в которые они были отправлены, в хронологическом порядке. Я считаю, что хронологический компонент очень полезен, если вы хотите знать, что вы изменили в своей системе.

В исходном ответе также использовались только команды "apt-get install", но недавно apt поддерживал прямые команды "apt install", которые не были захвачены ответом. Я сделал PCRE более мягким, включив в него все подходящие команды.

zcat /var/log/apt/history.log.*.gz | \
cat - /var/log/apt/history.log | \
grep -Po '^Commandline:(?= apt)(?=.* install ) \K.*|^Start-Date: \K.*' | \
grep -B1 "^apt" | \
grep -v -- "^--" | \
paste -d " "  - - | \
sort

На самом деле это сложнее, чем кажется, и на Ask Ubuntu есть довольно много похожих вопросов.

Я нашел это, глядя в /var/log/apt/history.log и старые версии этого журнала в формате gzip, любая вещь, установленная apt-get install Команда указана как установленная этой командой.

Так:

grep "apt-get install" /var/log/apt/history.log

Покажет вам все за период, который охватывает текущий журнал истории apt. Вам нужно будет gunzip ваши старые журналы, и grep те, чтобы собрать всю вашу информацию вместе. Все команды grep могут быть перенаправлены в текстовый файл, чтобы получить хороший список.

Это, вероятно, полезно только в том случае, если Software Center использует apt-get install при установке. Я знаю, что Центр программного обеспечения - это интерфейс для apt но не уверен, что он использует эту команду явно.

Эта команда выдаст список установленных вручную пакетов, а также тех, у которых были удалены их «автоматически установленные» обратные зависимости (например, если вы удалите метапакет ubuntu-server, его зависимости больше не будут помечаться как автоматические и будут теперь быть в этом списке):

      apt list --installed | grep -v automatic

Другими словами, приведенный выше список вернет все пакеты либо без обратных зависимостей, либо где они также помечены как установленные вручную.

Вот скрипт Ruby, который использует rdepends, чтобы проверить, является ли пакет зависимостью для другого установленного пакета. Это не скажет точно, что вы выбрали, но это не зависит от ваших файлов журналов (которые могли быть повернуты).

При установке пакетов, перечисленных в качестве корневых, будут установлены все пакеты, перечисленные в дочерних пакетах. Таким образом, вы должны получить почти (см. Недостатки ниже) тот же список пакетов.

В списке детей будут показаны пакеты, которые являются зависимостями других дочерних пакетов или корневых пакетов.

У этого подхода есть некоторые недостатки:

  • Некоторые пакеты могут не отображаться в качестве корневых, если они являются зависимостями какого-либо необязательного, рекомендованного вами выбранного пакета. Например, на моем сервере apache2 указан в детских пакетах, потому что у меня также есть libapache2-mod-php, libapache2-mpm-itk а также python-letsencrypt-apache установлены, которые имеют apache2 как зависимость.
  • Циклические зависимости (пакеты, которые прямо или косвенно зависят друг от друга) будут перечислены в дочерних пакетах (например: libapache2-mod-php а также libapache2-mod-php7.0). Есть раздел, в котором перечислены вероятные циклы (проверьте предки пакетов на 5 поколений), вы должны включить его, чтобы иметь тот же список пакетов (если я не пропустил что-то еще).
#!/usr/bin/env ruby

class ListRootPackages
  def run
    count = manual_marked_packages.count
    @dependencies ||= {}

    @root_packages ||= begin
      manual_marked_packages.each_with_index.map do |package, index|
        STDERR.print "   #{index + 1} / #{count} \r"

        intersection = manual_marked_packages & reverse_dependencies(package)

        if intersection.any?
          @dependencies[package] = intersection
          nil
        else
          package
        end
      end.compact
    end
  end

  def potential_cyclic_dependences
    run

    @potential_cyclic_dependences ||= @dependencies.keys.map do |package|
      package unless has_root_ancestor?(package, 5)
    end.compact
  end

  def has_root_ancestor?(package, level=0)
    return true if @root_packages.include?(package)
    return false if level.zero?

    @dependencies[package].any? { |parent| has_root_ancestor?(parent, level - 1) }
  end

  def root_packages
    run
    @root_packages
  end

  def dependencies
    run
    @dependencies
  end

  def manual_marked_packages
    @manual_marked_packages ||= parse_cli_list(`apt-mark showmanual`)
  end

  private

  def reverse_dependencies(package)
    parse_cli_list(`apt-cache rdepends #{package}`)[2..-1]
  end

  def parse_cli_list(list)
    list.split("\n").map(&:strip)
  end
end

list = ListRootPackages.new
list.run

puts "===== Root Packages (#{list.root_packages.count}) ====="
puts list.root_packages.join("\n")
puts

puts "===== Children packages (#{list.dependencies.count}) ====="
puts list.dependencies.map { |package, parents| "#{package}: #{parents.join(', ')}" }.join("\n")
puts

puts "===== Potential cyclic dependencies (#{list.potential_cyclic_dependences.count}) ====="
puts list.potential_cyclic_dependences.join(", ")

если кто-то захочет преобразовать это в Bash или Python, это было бы неплохо, поскольку Ruby реже устанавливается на серверах, чем Bash или Python.

Другие вопросы по тегам