7

Software Center somehow shows quite short list of installed packages. How to get it in text file?

I tried:

> 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

I know that I've installed few dozens packages, not thousands. I need in the list exactly packages I'd choosen without dependencies to review it.

UPDATE

Many thanks to @kos, I got finally the list with that command:

> 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
11

This doesn't answer the question exactly: it rather gives a command to list all the apt-get install commands ever run along with some advices on how to parse the list further in order to get a list of all the apt-get install command ever run excluding those run by Ubiquity, since the perfect solution for this task seems to not exist.

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: decompresses all the compressed apt logs in /var/log/apt, concatenates them and prints to stdout;
  • cat - /var/log/apt/history.log: appends /var/log/apt/history.log and prints to stdout;
  • grep -Po '^Commandline:(?= apt-get)(?=.* install ) \K.*': selects only the lines starting with Commandline: apt-get containing install with a leading and trailing space and prints the remainder of each selected line to stdout;

This will output the list of all the apt-get install commands ever run (the only undesidered output could be an apt-get-non-install command mentioning an install package, but that package doesn't exist (yet?), at least in the default repositories);

Note: In my installation (Ubuntu 15.04 64-bit), the first four commands listed are those run by Ubiquity during the installation; to exclude these, you may pipe the output to sed:

sed '1,4d'

So that the final approximate command for Ubuntu 15.04 64-bit would be:

zcat /var/log/apt/history.log.*.gz | cat - /var/log/apt/history.log | grep -Po '^Commandline:(?= apt-get)(?=.* install ) \K.*' | sed '1,4d'
  • This looks almost that I wanted, but it contains many lines --reinstall – zuba Oct 1 '15 at 11:25
  • zcat was what I was missing. Mine's a bit of a long-winded method in comparison! – Arronical Oct 1 '15 at 11:30
  • That looks fine, but there are also lines like -f, -y, -force-yes. Btw, hank you very much!!! I accept your answer. Can you check my updated command in the question? – zuba Oct 1 '15 at 11:36
  • Looking forward to see it! – zuba Oct 1 '15 at 11:51
  • Ok! And regards!!! – zuba Oct 1 '15 at 12:29
6
apt-mark showmanual

will give you a list of all manually installed packages without the dependencies - the important thing to take note of is that it will also show what package were installed during Ubuntu setup.

To write the output to a file:

apt-mark showmanual > somefile

There are actually many other ways, such as using this command

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

Although I have absolutely no idea how the above works ;)

To view packages installed by date:

Packages installed by date use cat /var/log/dpkg.log | grep "\ install\ > somefile"
Packages installed using dpkg use ls -l /var/log/dpkg* > somefile - this one is probably what you're looking for.

To view packages installed using dpkg:

This file contains the above information: /var/log/dpkg.log

  • I doubt I've choosen 1181 packages, really. ``` > apt-mark showmanual|wc -l 1181 ``` – zuba Oct 1 '15 at 10:59
  • @zuba The reason is that all the packages that were installed during Ubuntu setup are also marked manual. – Nephente Oct 1 '15 at 11:04
  • I get it. How can I select the packages I'd choosen manually after installation. Can I e.g. select packages with installation dates, to filter out those with dates after installation date? – zuba Oct 1 '15 at 11:06
  • @zuba I've now added how to view packages installed by date – TellMeWhy Oct 1 '15 at 11:19
  • @DevRobot. Could you provide a link to where you found that command? It's really nifty. I had no idea, about the initial-status.gz :-) – Nephente Oct 1 '15 at 11:19
2

This is actually more complicated than it seems, and there are quite a few similar questions on Ask Ubuntu.

I've found that looking in /var/log/apt/history.log and the older gzipped versions of that log, any thing installed by an apt-get install command is listed as installed by that command.

So:

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

Will show you all of them for the period that the current apt history log covers. You'll need to gunzip your older logs, and grep those to get all of your information together. The grep commands could all be redirected into a text file to give you a nice list.

This is probably only useful for your case if Software Center uses apt-get install when installing. I know that Software Center is a front end for apt but not sure it uses that command explicitly.

0

Here is a Ruby script that uses rdepends to check if a package is a dependency for another installed package. That will not tell exactly what you selected, but that does not depend on your logs files (which might have been rotated).

Installing packages listed as root packages will install all the packages listed in children packages. So you should end up with almost (see drawbacks below) the same packages list.

The children list will shows the packages that are dependencies of other children packages or root packages.

There are some drawbacks with this approach:

  • Some packages might not be listed as root when they are dependencies of some optional, recommended package you selected. For example, on my server apache2 is listed in children packages because I also have libapache2-mod-php, libapache2-mpm-itk and python-letsencrypt-apache installed which have apache2 as a dependency.
  • Cyclic dependencies (packages that directly or indirectly depends on each others) will be listed in Children packages (for example: libapache2-mod-php and libapache2-mod-php7.0). There is a section listing the probable cycle (check the package ancestries for 5 generations), you should include it to have the same list of packages (unless I've overlooked something else).
#!/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(", ")

if somebody wants to convert that to Bash or Python, that would be nice since Ruby is less commonly installed on servers than Bash or Python.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.