14

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
1

6 Answers 6

13

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'
2
  • 2
    This doesn't include any apt install commands. This will: zcat /var/log/apt/history.log.*.gz | cat - /var/log/apt/history.log | grep -Po '^Commandline:(?= apt(-get)?)(?=.* install ) \K.*' | sed '1,4d'
    – mbomb007
    Mar 1, 2021 at 16:41
  • Note that on Debian by default only one year of apt history is kept, so this will not return results beyond that. May 9, 2022 at 1:59
11
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

6
  • I doubt I've choosen 1181 packages, really. ``` > apt-mark showmanual|wc -l 1181 ```
    – zuba
    Oct 1, 2015 at 10:59
  • @zuba The reason is that all the packages that were installed during Ubuntu setup are also marked manual.
    – Nephente
    Oct 1, 2015 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, 2015 at 11:06
  • @zuba I've now added how to view packages installed by date
    – TellMeWhy
    Oct 1, 2015 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, 2015 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.

2

Here's a slight improvement to the accepted answer that lists the commands with the dates that they were issued on in chronological order. I find the chronological component very helpful if you want to know what you changed when on your system.

The original answer also took only "apt-get install" commands, but apt recently supported direct "apt install" commands which were not captured by the answer. I made the PCRE a bit more lenient to include all apt commands as well.

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
0
1

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 log 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.

1

This command will give a list of manually installed packages, as well as those where their "automatically installed" reverse dependencies has been removed (for instance, if you remove the ubuntu-server metapackage, its dependencies will no longer be marked automatic, and will now be on this list):

apt list --installed | grep -v automatic

In other words, the above list will return all packages with either no reverse dependencies, or where they are also marked as manually installed.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .