BedroomLAN

Tilde~A: Alexios' Homepage

Cleaning Up a Debian APT Archive Cache

You have a Debian, Ubuntu or similar installation, and your /var partition keeps getting full when you upgrade. You check /var/cache/apt/archives and find it full of the usual mix of current and old versions of downloaded packages. Somehow, they haven't been deleted after installation, or you keep downloading them but not installing them. You now need a quick and clever way of cleaning up this mess, so only the latest version of each package remains.

Solution

Here's an appropriate bash invocation:

find /var/cache/apt/archives/ -name '*deb' |
perl -ne 'print "$1\n" if /([^\/_]+)_/'|
sort -u |
while read a; do
    find /var/cache/apt/archives/ -name "${a}_*" | 
    sort -r | tail -n+1 | xargs -rp sudo rm -v;
done

For each package name, this will delete all but the latest .deb package. Obviously, if there's only one version of a package, it's not deleted. You will be asked to confirm each deletion.

If you're running this as root (naughty, naughty), remove the sudo from the second line. On Ubuntu, sudo is already set up for you, and you should use it. On Debian, you need to install and set it up yourself.

Discussion

Debian package names can't contain an underscore (_). Everything that comes after the underscore in a .deb filename is version (and platform) information. The first three lines of the script locate all packages and get their unique name stems. By using find rather than using something like ls /var/cache/apt/archives/*.deb, we avoid failure in case there are too many packages for the command line1. It's also a very bad idea to parse ls> output.

The second line finds everything between the last / and first _ of each line and prints that out. This is the package name.

The third line collects all of the package names, sorts them and prints out unique names so we don't duplicate any effort.

Then, the whiledone loop reads each of these stems, locates all the archived files matching the stem, sorts them in reverse order (i.e. most recent package first) and deletes all but the first one. It does this by running sudo rm -v via xargs The -p option prompts before executing the command and -r doesn't execute if the argument list is empty (i.e. nothing to delete).

This is known to fail for packages where the version string differs in length, for example if both versions 9.00 and 10.00 are present. Fixing this is a good exercise in shell scripting and using find. Over to you!
  • 1 On Linux, the maximum command line length varies. Before Linux 2.6.23, it used to be 131,072 bytes. Starting with Linux 2.6.23, there is no limit in the kernel, but it still reports the traditional limit anyway (tell bash getconf ARG_MAX to find out what it is). We shouldn't rely on this.