Cleanup /usr/lib/modules and /usr/lib/x86_64-linux-gnu

aptdebiankernellinuxUbuntu

I executed the command apt autoremove but those folders persist.

As the command "du -h -x –max-depth=1 /usr/lib | sort -hr | head -n 10" showed me, they are currently using almost 1G each:

858M    /usr/lib/modules
823M    /usr/lib/x86_64-linux-gnu

How can i cleanup this?
Thank you.

Best Answer

I needed to do this, as with over a year of using Linux on a Chromebook, /usr/lib/modules was taking over 10GiB of disk space (which is at a premium on this device) and I am only ever going to be running a single kernel instance anyway. The disk space necessary to run a single kernel was only ~500MiB, for contrast, ~5% of the disk space actually being used.

I came up with a solution myself, based on my distribution (KDE Neon, Ubuntu LTS-based), which consists of multiple Bash commands to do the following:

  • Detect the currently running Linux version
  • Detect linux-modules-* packages that belong to Linux versions not currently running
  • Uninstall all linux-modules-* packages (and depending linux-image-* packages) which are not running

Note that I've only tested this when already running the latest Linux kernel installed on my distribution. Your distribution might come with packages that depend on a meta-package, such as linux-generic-hwe-20.04 for Ubuntu 20.04 LTS-based distributions, and I haven't tested this script when running an older Linux after installing a newer one.

TL;DR:

sudo apt remove $(dpkg-query --show 'linux-modules-*' | cut -f1 | grep -v "$(uname -r)")

OK, But What Does That Mean?

The first command to run is uname -r. This prints the release number of your currently-running Linux kernel, in a format such as this:

$ uname -r
5.15.0-48-generic

Find out more at man uname.

The second command to look at is dpkg-query, which lets us query installed packages in different ways. You can use --list for a pretty, interactive display, but I chose to use --show to make scripting simpler.

$ dpkg-query --show 'linux-modules-*'
linux-modules-5.11.0-44-generic 5.11.0-44.48~20.04.2
linux-modules-5.11.0-46-generic 5.11.0-46.51~20.04.1
# etc.

Find out more at man dpkg-query.

A determined reader could probably figure out how to use the --showformat option to skip this step, but I preferred a more familiar approach - the cut command. The cut command simply takes standard input, an optional delimiter provided with -d (a tabulator character by default), and a field argument provided with -f. In this case, it takes the output of our dpkg-query command and returns the first column:

$ dpkg-query --show 'linux-modules-*' | cut -f1
linux-modules-5.11.0-44-generic
linux-modules-5.11.0-46-generic
# etc.

Find out more at man cut.

We pipe the output of that into the grep command, which lets us select lines that match a certain pattern - or, in this case, lines that don't match a certain pattern, using the -v|--invert-match option. The "$(uname -r)" returns a line like 5.15.0-48-generic, which is then used as the pattern to grep. This is how we select all linux-modules packages which are not currently running.

$ dpkg-query --show 'linux-modules-*' | cut -f1 | grep -v "$(uname -r)"
# = dpkg-query --show 'linux-modules-*' | cut -f1 | grep -v "5.15.0-48-generic"
linux-modules-5.11.0-44-generic
linux-modules-5.11.0-46-generic
# etc.

Find out more at man grep.

Finally, we just use this list as arguments to the sudo apt remove command, which is probably so familiar to people at this point it doesn't need much explanation:

$ sudo apt remove $(dpkg-query --show 'linux-modules-*' | cut -f1 | grep -v "$(uname -r)")
# = sudo apt remove linux-modules-5.11.0-44-generic linux-modules-5.11.0-46-generic [...]

... but in case those are not familiar to you, man sudo allows you to run a command as root, the system administrator (or theoretically another user), which is necessary to use man apt, which manages packages and dependencies on Debian (hence Ubuntu)-based distributions.