3

From /var/log/apt/history.log it is possible to retrieve a list of installed and removed packages within time x based on timestamps, but editing the file is rather annoying, so I'm looking for a (set of) command(s) to get the effective list of packages which have been installed after timestamp x_0(= packages which have been installed after timestamp x_0 minus packages which have been removed after timestamp x_0) in form of a list of package names.

software-center only displays changes chronologically and synaptic doesn't have a column which represents installation time. dpkg-query looks promising, but I'd appreciate some help from someone who can figure this out in minutes rather than days (the latter applies to myself).

I'm running Ubuntu 14.10.

  • Did you ever get around to doing this? (Interested in the solution or contributing to it...) But also too lazy to fully implement it all on my own... – Fabby Feb 1 '15 at 10:48
  • @Fabby two answers :) – A.B. Apr 29 '15 at 9:05
1

It seems that dpkg doesn't show explicitly any information about installation dates of packages.

So, for a single run I would use something like the following one-liner:

cat /var/log/apt/history.log |perl -lne 'next unless /^Start-Date: ([^ ]+)/ && $1 ge "2015-04-26" .. 1; next unless /^(Install|Purge|Remove): (.*)$/; $c = $1; $s = $2; $s =~ s/\([^\)]*\)//g; @packages = map { /^(.*?):/ ? $1 : $_} split /\s*,\s*/, $s; if ($c=~/^Install$/){ $h{$_} = 1 for @packages;} if ($c=~/^(Purge|Remove)$/) {delete $h{$_} for @packages;} END{print for sort keys %h;}'

Start date (x_0) has been hard-coded in the command ("2015-04-26").

For time to time usage more suitable would be a stand-alone script, like this installed_packages.pl:

#!/usr/bin/perl

# use as follows:
# ./installed_packages.pl '2015-04-26' /var/log/apt/history.log
# or
# ./installed_packages.pl '2015-04-26 16:08:36' /var/log/apt/history.log

use strict;
use warnings;

# the script expects start date as first argument
my $START_DATE = shift @ARGV;

# hash (dict) to accumulate installed & not removed packages 
my %installed;
# flag to mark the beginning of "interesting" period of time
my $start = 0;

# loop over lines from the input file
while (my $line = <>){
    # remove end-of-line character 
    chomp $line;

    # skip everything until date becomes greater (or equal) than our x_0
    $start ||= $line =~ /^Start-Date: ([^ ]+)/ && $1 ge $START_DATE;
    next unless $start;

    # we're only interested in lines like 
    # Install: tupi-data:amd64 (0.2+git02-3build1, automatic), tupi:amd64 (0.2+git02-3build1), libquazip0:amd64 (0.6.2-0ubuntu1, automatic)
    # or
    # Remove: aptitude-common:amd64 (0.6.8.2-1ubuntu4)
    # + separate action (install/remove/purge) from package list
    next unless $line =~ /^(Install|Purge|Remove): (.*)$/; 
    my ($action, $packages_str) = ($1, $2);

    # remove versions from the list (they're in parentheses)
    $packages_str =~ s/\(.*?\)//g;

    # split single line into array of package names
    my @packages = split /\s*,\s*/, $packages_str;
    # remove architecture name (comes after ':')
    s/:.*// for @packages;

    # if packages have been installed, add them all to the hash (dict) of installed packages
    if ($action =~ /^Install$/ ){
        $installed{$_} = 1 for @packages;
    }

    # if packages have been removed, remove them all from the hash (dict) of installed packages
    if ($action =~ /^(Purge|Remove)$/) {
        delete $installed{$_} for @packages;
    }
}

# print all installed and not removed packages, in alphabetical order
for my $p ( sort keys %installed ){
    print "$p\n";
}

Usage:

./installed_packages.pl '2015-04-26' /var/log/apt/history.log

or

perl ./installed_packages.pl '2015-04-26' /var/log/apt/history.log

For frequent interactive use I'd add validation of script arguments (format of start date), implement -h switch to display short help, and possibly convert start date to named switch (--start).

Good luck!

0

I took the source code of this response and slightly expanded.

The added value is that you also get purged and removed packages and the output can be filtered with grep.

List installed packages:

./installed_packages.pl '2015-04-28' /var/log/apt/history.log | grep Installed:

or this for purged or removed:

./installed_packages.pl '2015-04-28' /var/log/apt/history.log | grep -Ei '(Purged|Removed)'

Source code:

#!/usr/bin/perl

# use as follows:
# ./installed_packages.pl '2015-04-26' /var/log/apt/history.log
# or
# ./installed_packages.pl '2015-04-26 16:08:36' /var/log/apt/history.log

use strict;
use warnings;

# the script expects start date as first argument
my $START_DATE = shift @ARGV;

# hash (dict) to accumulate installed & not removed packages 
my %installed;
my %removed;
my %purged;
# flag to mark the beginning of "interesting" period of time
my $start = 0;

# loop over lines from the input file
while (my $line = <>){
    # remove end-of-line character 
    chomp $line;

    # skip everything until date becomes greater (or equal) than our x_0
    $start ||= $line =~ /^Start-Date: ([^ ]+)/ && $1 ge $START_DATE;
    next unless $start;

    # we're only interested in lines like 
    # Install: tupi-data:amd64 (0.2+git02-3build1, automatic), tupi:amd64 (0.2+git02-3build1), libquazip0:amd64 (0.6.2-0ubuntu1, automatic)
    # or
    # Remove: aptitude-common:amd64 (0.6.8.2-1ubuntu4)
    # + separate action (install/remove/purge) from package list
    next unless $line =~ /^(Install|Purge|Remove): (.*)$/; 
    my ($action, $packages_str) = ($1, $2);

    # remove versions from the list (they're in parentheses)
    # $packages_str =~ s/\(.*?\)//g;

    # split single line into array of package names
    my @packages = split /\s*,\s*/, $packages_str;
    # remove architecture name (comes after ':')
    s/:.*// for @packages;

    # if packages have been installed, add them all to the hash (dict) of installed packages
    if ($action =~ /^Install$/ ){
        $installed{$_} = 1 for @packages;
    }

    # if packages have been removed, add them all to the hash (dict) of installed packages
    if ($action =~ /^Remove$/) {
        $removed{$_} = 1 for @packages;
    }

    # if packages have been purged, add them all to the hash (dict) of installed packages
    if ($action =~ /^Purge$/) {
        $purged{$_} = 1 for @packages;
    }
}

# print all installed and not removed packages, in alphabetical order
for my $p ( sort keys %installed ){
    print "Installed: $p\n";
}

for my $p ( sort keys %removed ){
    print "Removed: $p\n";
}

for my $p ( sort keys %removed ){
    print "Purged: $p\n";
}
  • Good one! Upvoted! – Fabby Apr 29 '15 at 16:17

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.