330

I'd like to get a list of packages installed manually by apt or aptitude and be able to find out whether a foobar package was installed manually or automatically.

How can we do that from the command line?

4

20 Answers 20

347

You can use either of these two one-liners. Both yield the exact same output on my machine and are more precise than all solutions proposed up until now (July 6, 2014) in this question.

Using apt-mark:

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

Using aptitude:

comm -23 <(aptitude search '~i !~M' -F '%p' | sed "s/ *$//" | sort -u) <(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u)

Very few packages still fall through the cracks, although I suspect these are actually installed by the user, either right after the installation through the language localization setup or e.g. through the Totem codec installer. Also, the linux-header versions also seem to accumulate, even though I've only installed the non version-specific metapackage. Examples:

libreoffice-help-en-gb
openoffice.org-hyphenation
gstreamer0.10-fluendo-mp3
linux-headers-3.13.0-29    

How does it work:

  1. Get the list of manually installed packages. For aptitude, the additional sed strips out remaining whitespace at the end of the line.
  2. Get the list of packages installed right after a fresh install.
  3. Compare the files, only output the lines in file 1 that are not present in file 2.

Other possibilities don't work as well:

  • Using the ubuntu-14.04-desktop-amd64.manifest file (here for Ubuntu 14.04) instead of /var/log/installer/initial-status.gz. More packages are shown as manually installed even though they are not.
  • Using apt-mark showauto instead of /var/log/installer/initial-status.gz. apt-mark for example doesn't include the xserver-xorg package, while the other file does.

I used various other StackExchange posts as references, however none work as well as the above solution:

Both list more packages than the above solution.

EDIT: What to do if you've upgraded from a previous release:

If you've upgraded Ubuntu from one release to the next, you will probably need to adjust this process. In that case, I would check the manifest file of the newer release (see above) in addition to the initial-status.gz file from the current release. You can easily do that by just adding another comparison. Using just the manifest file will not work, as the manifest file unfortunately does not contain everything that the initial_status.gz file does (I checked).

22
  • 12
    This didn't work for me because /var/log/installer/initial-status.gz is missing. Also I want to know if this is depending on apts marking of manual or not?
    – Anwar
    Oct 29, 2016 at 8:20
  • 1
    Alas there is no manifest for server versions. Apr 10, 2017 at 13:22
  • 2
    Manifest files can be downloaded from releases.ubuntu.com
    – darkdragon
    Apr 6, 2020 at 21:34
  • 2
    This answer is the best I found until now. However, it (still) misses transient package suggestions (and recommendations). For example, when I apt install git-review, only git-review gets listed. So far, so good. When I apt remove git-review, the package git stays but is not listed. That is because git is a ‘suggests’ in the package libdpkg-perl (see /var/lib/dpkg/status). The same happens for if a package was installed with apt install --no-install recommends and later another package installs that recommendation, then it stays but gets not listed. No idea how to catch those. May 11, 2021 at 9:57
  • 2
    I originally installed an older version of Ubuntu and now I'm running 20.04, so I downloaded the manifest from releases.ubuntu.com/20.04/… and then I ran comm -23 <(apt-mark showmanual | sort -u) <(cat ~/Desktop/ubuntu-20.04.2.0-desktop-amd64.manifest | awk '{print $1}' | sort -u). Thanks!
    – bmaupin
    Aug 3, 2021 at 19:59
127

In newer versions of the package apt, there is also the apt-mark command

apt-mark showmanual
7
  • 62
    This shows way more packages than I have installed manually.
    – Umang
    Jul 7, 2014 at 11:05
  • 2
    @Umang You are right. I would say this wasn't like this when I wrote this answer. There is no reason on my system to consider linux-image-3.11.0-*-generic etc as manual Jul 8, 2014 at 11:23
  • 4
    @Umang maybe this will help you askubuntu.com/questions/432743/…, but the answer is not accepted. Fact is, that many packages of a fresh installation are already marked as manual. But there are still some strange things. To stay with my example: linux-image-3.13.0-24-generic is manual but the current linux-image-3.13.0-27-generic is automatic. It seems that an upgrade of a referencing package (in this case linux-image-generic, which changed the dependencies), the manual mark is automatically set Jul 8, 2014 at 11:42
  • 13
    @DanielAlder some packages of a fresh installation should be marked as manual. If no packages marked as manual, the entire system could be deleted with apt-get autoremove. This is definitely not what you want.
    – Anton K
    Dec 2, 2016 at 10:57
  • 3
    Wow. It's 2021 and I had to find this post to learn about apt-mark.
    – Hinz
    Oct 25, 2021 at 7:44
52

To get a list of all packages (not installed, installed by user or installed by default, across all PPAs), apt employs the following method:

apt list [option]

The possible options useful for this are:

--installed to display only the packages that are installed on the system (out of some 50,000+)

--manual-installed to list the packages that were explicitly installed by a command, either directly, or as dependencies.

Alternatively, you could do:

apt list --installed | grep -F \[installed\] to get a list of packages that resulted from user commands and their dependencies only, and to get additional information on them such as version and architecture supported (x86, x86_64, amd64, all, etc.)

2
  • 6
    Should be the accepted answer, for modern Ubuntues
    – Déjà vu
    Dec 29, 2021 at 10:48
  • 2
    This still appears to list packages included in the base installation, which were not explicitly installed by the user running apt install .... Apr 28, 2023 at 20:56
51

For Ubuntu 16.04, check out the log file /var/log/apt/history.log.

For example:

zgrep 'Commandline: apt' /var/log/apt/history.log /var/log/apt/history.log.*.gz

It's not perfect, but it's pretty good at making it clear exactly what I installed by hand. Put a -B 1 on the grep to see when it was installed.

Example output

Commandline: apt install postgresql-9.5-plv8
Commandline: aptdaemon role='role-install-file' sender=':1.85'
Commandline: apt install task
Commandline: apt autoremove
Commandline: apt install atom
Commandline: apt upgrade
Commandline: apt-get install asciinema
Commandline: apt install iperf3
Commandline: apt upgrade
Commandline: apt-get install chromium-browser
Commandline: apt install joe cpanminus build-essential postgresql libdbd-pg-perl libcrypt-openssl-bignum-perl libcrypt-openssl-rsa-perl libio-socket-ssl-perl libnet-ssleay-perl libssl-dev
Commandline: aptdaemon role='role-commit-packages' sender=':1.2314'
Commandline: apt install git
Commandline: apt install sqlite
Commandline: apt install whois
Commandline: apt install libdbd-pg-perl
Commandline: apt install perl-doc
Commandline: apt upgrade

Not sure if this picks up aptitude or not. It doesn't seem to pick up installs from the Ubuntu Software desktop app.

4
  • 2
    you say it's not perfect, but it is indeed beautiful Oct 20, 2021 at 17:39
  • This should be updated to be the accepted answer.
    – bomben
    Jun 24, 2022 at 18:21
  • You can parse this to get all install minus all remove/purge command lines: comm -23 <(zgrep "Commandline: \(apt\|apt-get\) install" /var/log/apt/history.log* | sed -n 's/^Commandline: \(apt\|apt-get\) install //p' | tr " " "\n" | sort -u) <(zgrep "Commandline: \(apt\|apt-get\) \(remove\|purge\)" /var/log/apt/history.log* | sed -n 's/^Comma ndline: \(apt\|apt-get\) \(remove\|purge\) //p' | tr " " "\n" | sort -u)
    – jmiserez
    Aug 10, 2022 at 11:23
  • 2
    Note that under default log rotation settings, apt only keeps the last 12 months of history. If you're dealing with a server that's a few years old, this approach can miss packages. You can edit the file /etc/logrotate.d/apt to change this retention period.
    – Nick ODell
    Dec 5, 2023 at 18:58
23

apt-mark showauto | grep -iE '^foobar$' will output "foobar" if the package was installed automatically, nothing otherwise.

aptitude search '!~M ~i' will list the packages that were not installed automatically. It's a pity aptitude won't be part of the default install on Ubuntu Desktop starting from 10.10.

8
  • aptitude search shows ALL packages not just the ones that are manually installed (I assume that's what the OP wanted)
    – Oli
    Aug 16, 2010 at 17:42
  • 1
    @Oli: look into aptitude search patterns; the pattern I'm using there should do exactly what the OP wants.
    – Li Lo
    Aug 16, 2010 at 17:44
  • I ran it. It shows a whole load of packages that aren't installed.
    – Oli
    Aug 16, 2010 at 17:46
  • 8
    Something isn't right with this, I'm using aptitude search '!~M ~i' and it lists 1043 packages. There is no way I installed that many packages manually. Sep 16, 2010 at 7:42
  • This definitely doesn't work as requested, prints pre-installed packages as well.
    – Irfy
    Nov 1, 2012 at 2:55
11

I would like to give a GUI solution.

enter image description here

  1. Open Synaptic Package Manager.

  2. Go to Status.

  3. Click Installed (manual).

It will give the list of packages installed manually by apt or aptitude.

Unfortunately I could not find any option in Custom Filters to find out whether a foobar package was installed manually or automatically.

If the package is under Installed but not under Installed (manual), then it was installed automatically. If the package is under Installed (manual), then it was installed manually.

10

The following script will print out all the packages that are not set to automatic install and hence were installed manually:

#!/usr/bin/python

try:
    import apt_pkg
except ImportError:
    print("Error importing apt_pkg, is python-apt installed?")
    sys.exit(1)

apt_pkg.init()
STATE_FILE = apt_pkg.config.find_dir("Dir::State") + "extended_states"
auto = set()
tagfile = apt_pkg.TagFile(open(STATE_FILE))
while tagfile.step():
    pkgname = tagfile.section.get("Package")
    autoInst = tagfile.section.get("Auto-Installed")
    if not int(autoInst):
        auto.add(pkgname)
print("\n".join(sorted(auto)))

it is based on how apt-mark prints out the automatically installed packages.

4
  • Kudos to you fine sir. This actually works, in contrast to the accepted answer.
    – Irfy
    Nov 1, 2012 at 2:53
  • show just a couple of package for me --- definitely missing a lot of them.
    – Rmano
    Jan 23, 2014 at 17:36
  • Same here, definitely missing manually installed packages, right after I installed them. Mar 2, 2016 at 1:23
  • Using sys.exit(1) without import sys might result in an error in newer versions of python. Either import sys or use exit(1).
    – Videonauth
    Nov 26, 2017 at 14:40
5

As several people have commented, apt-mark showmanual seems to be a bit buggy (and I reported it as bug 727799). When I'm using it, it actually reports a lot of stuff that isn't even logged in /var/lib/apt/extended_states (where this is supposed to be stored) and apt-get isn't logging things as installed in /var/lib/apt/extended_states (just in /var/lib/dpkg/status). The python script by txwikinger above draws from /var/lib/apt/extended_states directly but if you're using it today the syntax might not work (mine just started generating errors with Kubuntu 13.10). Updated syntax is:

#!/usr/bin/python
import sys

try:
    import apt_pkg
except ImportError:
    print "Error importing apt_pkg, is python-apt installed?"
    sys.exit(1)

apt_pkg.init()
STATE_FILE = apt_pkg.config.find_dir("Dir::State") + "extended_states"
auto = set()
tagfile = apt_pkg.TagFile(open(STATE_FILE))
while tagfile.step():
    pkgname = tagfile.section.get("Package")
    autoInst = tagfile.section.get("Auto-Installed")
    if not int(autoInst):
        auto.add(pkgname)
print "\n".join(sorted(auto))

For me this was a very short list of 5 items which doesn't seem to be accurate either.

1
  • 1
    Using sys.exit(1) without import sys might result in an error in newer versions of python. Either import sys or use exit(1).
    – Videonauth
    Nov 26, 2017 at 14:40
3

If you're in a VM (Virtual Machine), then the following might work better for you:

egrep 'apt(-get)? +install' /var/log/apt/history.log

That finds software you installed both via apt and apt-get. If you'd like to include aptitude too, this should work:

egrep 'apt(-get|itude)? +install' /var/log/apt/history.log

(But don't think this'd find packages installed directly via dpkg — which I don't really do anyway.)

Rationale: If the Virtual Machine already included some default software installed by the VM maintainers (in the base image), but not by you, then, this answer won't show the software they installed (well at least not in the VMs I'm using), only the software you installed.

The other answers here, which uses e.g. apt-mark showmanual or aptitude search '!~M ~i' or apt list --manual-installed, in my case, in a VM, showed 90% to me uninteresting packages that I didn't install — instead, some of the VM base image maintainers did (I presume).

2
  • This is true. I used history | egrep 'apt(-get|itude)? +install'
    – VidathD
    Jun 3, 2021 at 9:16
  • I think your search expression misses apt -y install.
    – bers
    Jan 20, 2023 at 11:31
2

If no one gives you a nice answer using a apr-something command you can do it the hard way. Apt-get stores its info in /var/lib/apt/extended_states. Any file that is installed automatically will be added to this file. If you install a package already in this file manually, the package will remain in this file but with Auto-installed: 0 in the second line. It's not deleted.

Note: As expected better answers that are likely to work if file placement changes have appeared. I keep mine just in case the info on the file location is useful.

2
  • 1
    No. I took a quick look at that file to find that liferea was marked as auto-installed. I did an apt-get install liferea and it didn't install but I got output that was something to the effect of "marked as manually installed". Now liferea is still in the file, except the next line has a 0 instead of a 1. Also, you should change your regex pattern to " foobar$" instead of just foobar.
    – Umang
    Aug 17, 2010 at 13:21
  • That's true. My fault, in my system there is no line with 0, but it should be a rare happening. I update the answer just in case. Aug 17, 2010 at 16:14
2

An updated version of @jmiserez' answer:

comm -23 \
    <(apt-mark showmanual | sort -u) \
    <(grep -oP '^(?:Package|Depends):\s+\K.*' /var/log/installer/status \
        | grep -oP '[^\s,()]+?(?=(?:\s+\([^)]+\))?+(?:,|$))' \
        | sort -u)

The log is no longer stored at /var/log/installer/initial-status.gz and the original did not omit dependent packages. The list it produces will include packages you didn't manually install, but it's a more manageable length and still very useful.

1
  • The answers that are based on initial-status.gz (or in this case its equivalent) are the best here, but become increasingly irrelevant if you have upgraded the installation to new releases over the years because new packages brought in by the upgrades will be included. I feel a similar solution using the current version's manifest file might be more useful in such cases Jan 2 at 0:21
2

After googling a lot, I've managed to assemble this script. It works alright for me:

#!/bin/bash

# List of all packages currently installed
current=$(dpkg -l | awk '{print $2}' | sort | uniq)

# List of all packages that were installed with the system
pre=$(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort | uniq)

# List of packages that don't depend on any other package
manual=$(apt-mark showmanual | sort | uniq)

# (Current - Pre) ∩ (Manual)
packages=$(comm -12 <(comm -23 <(echo "$current") <(echo "$pre")) <(echo "$manual") )

for pack in $packages; do
    packname=$(echo $pack | cut -f 1 -d ":")
    desc=$(apt-cache search "^$packname$" | sed -E 's/.* - (.*)/\1/')
    date=$(date -r /var/lib/dpkg/info/$pack.list)

    echo "# $desc"
    echo "# $date"
    echo "sudo apt-get install $pack"
    echo -e ""
done
3
  • You could use sort -u instead of sort | unique. As apt-markdoes not display architecture, you should strip it from dpkg's output before the set operations (or use dpkg-query -W -f='${Package}\n'). Besides, dpkg may list some packages that are not installed currently. As for "desc", you could use `dpkg-query -W -f='# ${binary:Summary}\n' $pack, which is faster.
    – jarno
    Dec 20, 2015 at 15:54
  • Oh, apt-markmay display architecture for some packages, but not for so many as dpkg -l.
    – jarno
    Dec 20, 2015 at 23:47
  • apt-cache search is slow. Getting a list of installed dates in advance using something like help.ubuntu.com/community/ListInstalledPackagesByDate might be more efficient
    – opticyclic
    Aug 24, 2017 at 3:37
2

Compiled from the awesome answers by others in this thread and additional info from the internet I assembled a command that fits my needs and perfectly replicates my apt history:

ls /var/log/apt/history.log* | sort --version-sort | xargs -d '\n' zgrep -B 1 'Commandline: apt'

So, first of all, it outputs history in chronological order, e.g.

/var/log/apt/history.log.1
/var/log/apt/history.log.2
...
/var/log/apt/history.log.10

You can add --reverse param to the sort to sort files in reverse order. That way you'll have oldest commands on the top of the list. Plus it has date of the command.

Kudos to @s1037989 and @iruvar

1

As Li Lo said, apt-mark showauto should get you a fat list of things automatically installed.

Now to show the things that are installed manually, it turns out there's a lovely simple search modifier for aptitude. But you don't want to to do that. You want to write a huge bash command that does some rocket science.

Note: This is more an illustration of how cool you'll look busting out massive bash commands to all your friends.

comm -3  <(dpkg-query --show -f '${Package} ${Status}\n' | \n
grep "install ok installed" | cut --delimiter=' ' -f 1) <(apt-mark showauto)

I broke it onto two lines for readability. What does this do?

  • First we query dpkg for a list of packages that are installed.
  • We filter those for the ones that are actually installed (not just residual config)
  • We chop off the status
  • We compare that list with the automated list from apt-mark
  • We rock out because we can.
3
  • I doubt this is accurate, since dpkg often shows packages that are not installed
    – txwikinger
    Aug 16, 2010 at 17:47
  • I know what you mean but my bash-fu isn't strong enough. I know you could show the status from dpkg-query, grep that down and then slice off the status. I'll have a go.
    – Oli
    Aug 16, 2010 at 17:49
  • comm -3 <(dpkg -l | grep '^ii' | cut -d \ -f 3|sort) <(apt-mark showauto|sort) is properly better ;) Aug 16, 2010 at 17:54
1

This gets you a list of manual installed packages and its corresponding version

apt list --manual-installed | sed 's/\// /' | awk '{print $1 "=" $3}'
1
  • Really should be MUCH higher voted!
    – Auspex
    Aug 9, 2023 at 20:30
0

Not sure if this is helpful, but to find packages that were recently installed manually by the current user, search the history. E.g., for bash:

$ history | egrep '\bapt\b'

Modify the grep to check for specific packages.

1
  • 2
    Not sure why this answer doesn't have more love. All the other answers here gave me a list that included lots of dependencies or didn't work. This is simple, and as long as your history is maintained, it's sufficient.
    – Greg
    Sep 4, 2022 at 21:15
0

If you installed all your packages from the terminal using apt, you could throw a simple regex searching for apt install * at the contents of /var/log/apt/history.log and see what it gobbles up. The regex might be as simple as: Commandline: apt install [\w -]+ (following the log syntax of apt on Ubuntu 16.04)

0

From Ubuntu 22.04 and onwards, you could take care of this using a more modern apt front-end called nala (for 22.04 you have to enable the "universe" repository).

sudo apt install nala

From this point, use nala to install new packages on your system, using:

sudo nala install <package-name>

Leave security updates etc. to the unattended-upgrades package.

Now, when you run the command nala history, you get a list of the commands run with nala, including installed packages. To filter only new installations, use:

nala history | grep install

An added bonus of the history feature is that you can undo any step in the history, so that you can reverse package installation procedures - something that is unnecessarily hard using apt itself.

-1

I have found an elegant method for doing this.

Just output the ~/.bash_history file with the grep command to sort them out:

cat .bash_history | grep "apt install"

Conveniently, you can look out for an apt-get too.

An example output, I have:

sudo apt install -f
sudo apt install vim 
sudo apt install dconf
sudo apt install dconf-editors
sudo apt install dconf-editor
sudo apt install nmap
sudo apt install python-tk
sudo apt install python-tk
-2

This will list all manually installed packages without: dependencies, uninstalled packages, packages installed during system installation.

unopts() {
  in=`cat`
  echo "$in" | sed -r 's/ --[^ ]+//g;s/ -[^ ]+//g'
}

list() {
  cat '/var/log/apt/history.log' |
  grep --color=never -v '\-o APT::Status-Fd=4 \-o APT::Keep-Fds::=5 \-o APT::Keep-Fds::=6' |
  egrep --color=never "Commandline: apt-get.* $1" |
  sed -r "s/Commandline: apt-get//;s/ $1//" |
  unopts |
  tr ' ' '\n' |
  sed '/^$/d'
}

hapt() {
  tmp=`mktemp -d`
  installed=$tmp/installed
  deleted=$tmp/deleted
  dpkg=$tmp/dpkg
  list 'install' > $installed
  list '(remove|purge|autoremove)' > $deleted
  dpkg --get-selections |
  grep -v 'deinstall' |
  cut -f 1 > $dpkg
  while read package
  do
    sed -i "0,/$package/{//d;}" $installed
  done < $deleted
  while read package
  do
    if [ -z "`grep --color=never "^$package$" $dpkg`" ]
    then
      sed -i "0,/$package/{//d;}" $installed
    fi
  done < $installed
  cat $installed
  rm -r $tmp
}

You must log in to answer this question.

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