767

Every time I install a new Linux kernel, it gets left in the grub_config, making the boot menu longer each time.

I know I can manually search through the installed packages and remove them.

Does Ubuntu provide any easier way to clean them up or keep them from showing in the boot list?

13
  • 10
    There is an ubuntu command called purge-old-kernels to do the job. See my answer for more information.
    – jarno
    May 7, 2015 at 11:43
  • 31
    sudo apt-get autoremove should do the trick on Ubuntu 14.04+
    – hobs
    Dec 1, 2015 at 17:17
  • 1
    The accumulation of old kernels is a bug, with fix in progress: bugs.launchpad.net/bugs/1357093 . When the fix is released, older kernels will autoremove by default.
    – user535733
    Dec 31, 2015 at 17:52
  • 1
    @hobs The command does not do the trick for me in Ubuntu Studio 14.04, if the kernels have not been installed automatically, but by Software Updater.
    – jarno
    May 27, 2016 at 9:38
  • 2
    I keep returning to this page... the comment by @hobs only works if your kernels were auto-installed - however you make sudo apt-get autoremove --purge the answer by following the apt-mark advice on https://help.ubuntu.com/community/RemoveOldKernels
    – earcam
    Jul 2, 2019 at 19:32

40 Answers 40

1
2
0

The following string of commands will purge any installed linux kernels except the currently running one (grep -v uname -r) and the lastest available kernel (dpkg -l | .... | tail -1):

dpkg -l | grep -E linux-image-.*-generic | cut -d ' ' -f3 | grep -v `dpkg -l | grep -E linux-image-.*-generic | cut -d ' ' -f3 | tail -1` | grep -v `uname -r` | xargs apt-get -y purge

I use this to keep desktop's boot volumes relatively clean, but in a server situation you'd probably want to expand the logic and write some additional scripting to maintain a list of the last X kernels the server has booted.

Something like a startup script that does:

uname -r >> /root/bootedkernels
cat /root/bootedkernels | sort -u | tail -3 > /root/bootedkernels # Keep the last 3 booted kernels

and then use:

dpkg -l | grep -E linux-image-.*-generic | cut -d ' ' -f3 | grep -vf /root/bootedkernels | grep -v `dpkg -l | grep -E linux-image-.*-generic | cut -d ' ' -f3 | tail -1` | grep -v `uname -r` | xargs apt-get -y purge
3
  • Simpler form would be sudo apt-get purge $(dpkg-query -W -f'${Package}\n' 'linux-image-[0-9]*' | head -n -1 | grep -v $(uname -r)), but even that raises questions: Can you rely on that dpkg lists newest kernel last? Can you rely on matching the current version as such regular expression? A dot in version string matches any character. What if the package name has one more character in version number than the current version? To be strict, you had better use uname -r | sed -r -e 's/\./\\./g' -e 's/.*/-&($|-)/' as the regular expression to match in the last grep command.
    – jarno
    May 16, 2015 at 14:15
  • Besides, the script does not purge any linux-header packages or other related packages.
    – jarno
    May 16, 2015 at 14:25
  • DO NOT USE THIS! It will remove old kernels without question. I tried without -y but then the command breaks before executing
    – rubo77
    Jul 25, 2019 at 9:05
0

If you are using ansible to control the machines, this playbook might be helpful.

---
 - hosts: all
   become: yes
   tasks:
    - name: "Run apt-get autoremove"
      apt: 
        name: linux-image-generic
        autoremove: yes
        state: present 
        update_cache: yes
        cache_valid_time: 3600
0

Rather use apt, the cli frontend for humans, than apt-get to purge old kernel images:

$ sudo apt autoremove --purge
...
The following packages will be REMOVED:
  linux-headers-4.4.0-51* linux-headers-4.4.0-51-generic* linux-image-4.4.0-51-generic* linux-image-extra-4.4.0-51-generic*
2
  • What's the difference here between apt and apt-get? (Note, apt is not available on a plain 12.04 installation.)
    – mwfearnley
    Feb 24, 2017 at 9:24
  • @mwfearnley For basic difference, see this answer When I was researching this, apt-get did not purge the old kernels for me. apt did, yet I also may have used them differently.
    – k0pernikus
    Mar 1, 2017 at 11:56
0

I give two safer variations of the methods in other answers: one using synaptic manager and the other using terminal.

With these variations you only remove packages that the system identifies as removable. There is no risk you remove linux kernels that are currently used—as it happened to me some weeks ago ;-(

Using Synaptic Manager

Instead of searching linux-image over all installed packages, select the autoremovable packages (See red ellipse in the picture below). Now from this list remove the linux-image you want.

enter image description here

Using terminal

Similarly, if you are removing kernels on terminal, show only the autoremovable kernels by running

 sudo apt-get -s autoremove | grep linux-image

And then remove whichever kernel linux-image-x.x.x-x-generic you want to remove from the given list by running

 sudo apt-get purge linux-image-x.x.x-x-generic 
0

To remove the kernels that were automatically installed via regular system updates, open terminal and run:

sudo apt autoremove --purge

To know your current kernel release run uname -r and also u can run uname --help to read more about all uname commands

You can also run df -h to show you file system drivers, similarly you can run df --help for more.

To enable automatic removing of old kernels: Edit the config file using gksu

gksudo gedit /etc/apt/apt.conf.d/50unattended-upgrades

When the file opens, uncomment the following line and change the value to true:

//Unattended-Upgrade::Remove-Unused-Dependencies "false";

If you need to install gksu, you can run sudo apt install gksu

To clear old packages we can use sudo apt-get clean

For More, visit http://ubuntuhandbook.org/index.php/2016/05/remove-old-kernels-ubuntu-16-04/

0

As @jarno and @earcam mentioned in their comments on the question, you first want to ensure all your linux kernel packages are marked as having been autoinstalled:

sudo apt-mark auto '^linux-.*-4\.12\.0-12(-generic)?$'

Then the normal apt-get autoremove command should work.

sudo apt-get autoremove --purge

Read the docs for more details.

0

I use unattended-upgrades so I really liked Qwerty's answer that configures it to uninstall old kernel packages automatically.

However there was one issue: after a new kernel is installed, this process would uninstall the package for the currently running kernel!

That doesn't break the OS entirely. In fact I rarely noticed it had happened, until I needed to hot-load a module (e.g. by plugging in a USB device) and then the module could not be found.

As a solution to this, I created a script to generate a virtual package currently-installed-kernel which effectively pins the current kernel package until the next boot.

The script is called pin-current-kernel-with-package.sh. Here is the latest version (probably) and the first version (definitely).

Just save that script somewhere, and add it to your bootup process. For example, save it in /usr/local/bin/pin-current-kernel-with-package.sh and then edit /etc/rc.local and add the following line:

bash /usr/local/bin/pin-current-kernel-with-package.sh

Now your running kernel package will never be uninstalled!

1
  • More recent versions of unattended-upgrades might be more intelligent about this now, so you might not need this script. link Mar 18, 2020 at 4:02
0

I'm using this remove_kernel script for removing old versions of kernel:

#!/usr/bin/env bash

if [ -z "${1}" ]; then
  echo 'Choose one of kernels as command line parameter:'
  ls -l /boot | grep initrd | grep '^-r' | awk -F'-' '{print$8"-"$9}'
  exit 1
else
  KRNL="${1}"
fi

echo 'These files will be deleted:'
echo '------'
dpkg --list | egrep -i "$KRNL" | awk '{print$2}'
echo '------'
echo "  Version to remove: ${KRNL}"
echo "  Current version: $(uname -r | awk -F'-' '{print$1"-"$2}')"
echo '------'
printf 'Do you want to proceed [enter y to continue]: '
read iamagree

if [ "${iamagree}x" == "yx" ]; then
  sudo apt-get -y --purge remove $(dpkg --list | egrep -i "$KRNL" | awk '{print$2}' | xargs)
else
  echo "cancelled"
fi

Usage:

$ remove_kernel
Choose one of kernels as command line parameter:
5.19.0-35
5.19.0-38
$ remove_kernel 5.19.0-35
These files will be deleted:
------
linux-headers-5.19.0-35-generic
linux-hwe-5.19-headers-5.19.0-35
linux-image-5.19.0-35-generic
linux-modules-5.19.0-35-generic
linux-modules-extra-5.19.0-35-generic
------
  Version to remove: 5.19.0-35
  Current version: 5.19.0-38
------
Do you want to proceed [enter y to continue]: y
...

Checked with Ubuntu 22.04.2 LTS

0

Read all the answer before executing the commands.

How I did it :

First get the kernal you are using uname -r

List the kernels, and note down the kernel that is just older (version 5.15.0-35 when you run the 5.15.0-36 - see the 35 and 36 at the end?) and another one: 5.14.0-46 (the latest of the 5.14 serie). That way, you want to keep two versions to revert to if needed).

(as a reminder : grep -v : if you want to find something which doesn’t match a given pattern, grep allows doing just that with -v flag)

 dpkg --list | egrep -i 'linux-image|linux-headers'

Remove the kernel unwanted. Note that the

 sudo apt-get --purge remove $(dpkg --list | egrep -i 'linux-image|linux-headers' | awk '/ii/{ print $2}' | grep -v `uname -r` | grep -v 5.15.0-35 | grep -v 5.14.0-46 )

the following might not be necessary, but it freed up space for me too - even if it should be the same than the set of command before

 dpkg -S "linux-image" 
 sudo apt-get --purge remove $(dpkg -S "linux-image" | cut -f'1' -d':' | grep -v 5.11 | grep -v 5.15.0-35 | grep -v 5.14.0-46 )

At the end, do :

 sudo apt autoremove
-2

Here's the script I use to keep 2 kernel packages installed (i.e. the current one and the previous one). It also removes the initrd-VERSION-generic.old-dkms files left around by DKMS, which can fill-up a small boot partition.

The script:

echo "**Removing -generic.old-dkms files from /boot**" && rm -f /boot/*-generic.old-dkms # if using DKMS it creates initrd-VERSION-generic.old-dkms in /boot and doesn't clean them up, meaning after a few kernel upgrades /boot can become full
OLDKERNEL=$(ls -tr /boot/vmlinuz-* | head -n -2 | cut -d- -f2- | awk '{print "linux-image-" $0}')
OLDHEADERS=$(ls -tr /boot/vmlinuz-* | head -n -2 | cut -d- -f2- | sed 's/-generic//g' | awk '{print "linux-headers-" $0}')
OLDHEADERS=${OLDHEADERS//-pae/} # remove -pae string as linux-header packages don't have it in their names
if [ -n "$OLDKERNEL" -o -n "$OLDHEADERS" ]; then
apt-get -q remove --purge $OLDKERNEL $OLDHEADERS
echo "**Finished removing old kernels**"
else
echo "**No old kernels found**"
fi
1
2

You must log in to answer this question.

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