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:
- Get the list of manually installed packages. For aptitude, the additional
sed
strips out remaining whitespace at the end of the line.
- Get the list of packages installed right after a fresh install.
- 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).
According to the documentation you can add a config file to /etc/apt/apt.conf.d/
named no-cache
containing Dir::Cache "";
and Dir::Cache::archives "";
according to manual of apt.conf
. There is a bug report raising issues with this method, and I don't recommend it.
There is one remaining method according to this tutorial:
echo 'DPkg::Post-Invoke {"/bin/rm -f /var/cache/apt/archives/*.deb || true";};' | sudo tee /etc/apt/apt.conf.d/clean
This will carry out an rm
command just before apt quits.
Best Answer
The
{} \;
syntax that you have guessed is specific to thefind
command and won't work in this context. You could usexargs
ex.Actually
xargs
has its own{}
-like syntax that you could use here, i.e.although it is redundant in this case (it's useful for cases where you want to substitute the piped value at a point other than the end of the command).
However the
apt-cache search
command is almost certainly not what you want here - it will search the entire (online) catalog for packages that match each of the results ofapt list --installed
. Even if you restrict the scope of the search using--names-only
you will still get many false positives (i.e. substring matches between packages that ARE installed and packages that AREN'T). It will also be horribly inefficient.For this particular task I'd skip
apt
altogether and use the lower-leveldpkg-query
command ex.which will be much more efficient (only traverse the package list once) and will be strictly limited to the local package catalog.
If you want to limit the output to packages that are currently installed, add the
db:Status-Abbrev
field and filter on that e.g.or