46

I have old Linux kernel versions that I don't use so I was trying to remove them.

List of installed kernels from dpkg --list | grep linux-image

linux-image-5.4.0-26-generic (5.4.0-26.30)   
linux-image-5.4.0-33-generic (5.4.0-33.37)
linux-image-5.4.0-37-generic (5.4.0-37.41)
Zanna
  • 70,465
  • 2
    Does sudo apt autoremove help? Which kernels are you asking about? – Pilot6 Jun 24 '20 at 12:31
  • 1
    Have you tried sudo apt autoremove? Please edit your question and add all the new information. Also indicate if you installed the kernels manually or something special. – user68186 Jun 24 '20 at 12:33
  • 1
    These are regular Ubuntu kernels. autoremove should remove them. – Pilot6 Jun 24 '20 at 12:48
  • 1
    Hmmm. Show us complete output. dpkg --list output includes kernels that have already been removed. The first column will indicate which packages are removed (rc) and which are installed (ii). – user535733 Jun 24 '20 at 13:17
  • 1
    There are a couple of excellent kernel removal manager type scripts around. I used the server version from here, for a long time, but now use this one. Note that I can not use autoremove, as it misbehaves when one uses mainline kernels. The manual method becomes tedious when trying to clean up 100 kernels. – Doug Smythies Jun 24 '20 at 13:48
  • For me, the system updater removes them automatically sometime after installing new kernel version. – raj Jan 17 '22 at 17:00
  • If you googled here it's probably some bug of synaptic. I get an error when try to remove an old kernel version with synaptic, but removing it with apt purge works. – quant2016 May 03 '22 at 19:26

11 Answers11

57

Here are the steps to remove unused kernels.

Check what current kernel You run:

uname -a
Linux blackhole 5.6.13-050613-lowlatency #202005141310 SMP PREEMPT Thu May 14 13:17:41 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

I am running 5.6.13-050613-lowlatency

List all installed kernels in Your OS:

dpkg --list | egrep -i --color 'linux-image|linux-headers|linux-modules' | awk '{ print $2 }'
linux-headers-5.6.11-050611
linux-headers-5.6.11-050611-lowlatency
linux-headers-5.6.13-050613
linux-headers-5.6.13-050613-lowlatency
linux-image-unsigned-5.6.11-050611-lowlatency
linux-image-unsigned-5.6.13-050613-lowlatency
linux-modules-5.6.11-050611-lowlatency
linux-modules-5.6.13-050613-lowlatency

Uninstall kernels You don't need:

sudo apt purge linux-headers-5.6.11-050611  linux-headers-5.6.11-050611-lowlatency linux-image-unsigned-5.6.11-050611-lowlatency linux-modules-5.6.11-050611-lowlatency
  • dpkg --list | egrep -i --color 'linux-image|linux-headers|linux-modules' | awk '{ print $2 }'. Really? Doesn't ls -1 /boot/vm* list your kernels including the current one? – Paul Benson Jun 24 '20 at 14:31
  • @PaulBenson Your command does not list packages. So You can't use these names in apt or dpkg to uninstall kernels. – Michal Przybylowicz Jun 24 '20 at 16:32
  • 7
    Isn't there an automated way to do that? I have more than 50 kernels installed in the list, many with un tag. – staticdev Jul 27 '20 at 15:01
  • While this seems tedious, it appears to be the only viable way. I would have loved to do it automatically, but I am unable to find a nice script for that. My hacky workaround is to use sudo apt-get purge linux-*-*-5.* (feel free to remove one -* to catch some other modules and do the same with 4.*) and manually check the output. This will get the desired packages, but might be too aggressive - i.e. check the output carefully to avoid a system suicide. – Betaminos Apr 13 '21 at 07:51
  • Sorry for the double comment, StackExchange won't let me edit the comment after the 5 min mark. I have found this nice script: https://www.tecmint.com/remove-old-kernel-in-debian-and-ubuntu/ (i.e. purge-old-kernels as a script included in the package byobu). This might help, but I have already purged all old kernels so can't test it for now. – Betaminos Apr 13 '21 at 08:09
  • Suppose I built and installed a newer kernel. I then boot under an older one and use this command. The new one is not listed, despite being listed in GRUB. Does this mean it didn't install properly? (I am troubleshooting issues with the new kernel not booting properly). – MadPhysicist Jul 23 '21 at 08:24
  • thanks. it worked for me – karthik nair Aug 06 '21 at 17:42
  • Shorthand (use at own risc!): sudo apt remove --purge $(dpkg --list | egrep -i --color 'linux-image|linux-headers|linux-modules' |grep -v $(uname -r)| awk '{ print $2 }') – gkephorus Nov 03 '22 at 11:25
40

You can try out this script

remove_old_kernels.sh

#!/bin/bash
# Run this script without any param for a dry run
# Run the script with root and with exec param for removing old kernels after checking
# the list printed in the dry run

uname -a IN_USE=$(uname -a | awk '{ print $3 }') echo "Your in use kernel is $IN_USE"

OLD_KERNELS=$( dpkg --list | grep -v "$IN_USE" | grep -Ei 'linux-image|linux-headers|linux-modules' | awk '{ print $2 }' ) echo "Old Kernels to be removed:" echo "$OLD_KERNELS"

if [ "$1" == "exec" ]; then for PACKAGE in $OLD_KERNELS; do yes | apt purge "$PACKAGE" done else echo "If all looks good, run it again like this: sudo remove_old_kernels.sh exec" fi

Run it like this for a dry run:

remove_old_kernels.sh

If all looks good, run it again like this:

sudo remove_old_kernels.sh exec
rubo77
  • 32,486
Alex Burdusel
  • 1,502
  • 2
  • 17
  • 24
  • Excellent, it worked perfect with PopOS 20.04 – hrnnvcnt Nov 11 '21 at 16:51
  • headers and modules are also getting deleted other than generic. How to handle that situation? – Jinna Baalu Dec 02 '21 at 17:51
  • You can change the script to only grep for the linux-image if you really want to keep the others – Alex Burdusel Dec 03 '21 at 22:05
  • Whenever I run this script, and it deletes an entry, I am getting stuck unable to press a selection on the menu about modifying grub files. Is there a way to go about fixing that? When I do manual delete of a kernel, I am able to make a selection in that menu to proceed. – MadPhysicist Mar 14 '22 at 08:20
  • 1
    Works like a charm on ubuntu 20.04 – Andy Mar 18 '22 at 15:34
  • This script has an issue, that it tries to remove the following packages:
    • linux-headers-generic
    • linux-image-generic

    and my kernel is 5.17.5-76051705-generic, and it tried to remove linux-headers-5.17.5-76051705. I suppose it needs to filter out these packages as well.

    Otherwise this is the perfect script! It removed a lot of old packages i had on my system. But sadly dpkg doesn't want to remove the directories of the modules...

    – eitch May 19 '22 at 05:36
  • why the loop? wouldn't this be more fitting? apt purge "$PACKAGE" $OLD_KERNELS then apt would remove them in one run and show how much space is freed summarized – rubo77 Jan 04 '23 at 23:10
  • I created an enhanced version of this script in https://github.com/rubo77/remove-old-kernels – rubo77 May 30 '23 at 09:46
13

Just taking Michal's answer a little further. I didn't want to type the kernels to delete everytime so I decided to use files instead.

Write all the current kernels you have on a file.

dpkg --list | egrep -i --color 'linux-image|linux-headers|linux-modules' | awk '{ print $2 }' > kernels.txt

Filter your currently used kernel out of the file using grep.

grep -v $(uname -r) kernels.txt > kernels_to_delete.txt

Verify your current kernel is not present in the delete list. Don't skip this. Ensures you don't mistakenly delete all the kernels.

grep $(uname -r) kernels_to_delete.txt

Delete all the unused kernels in one go.

cat kernels_to_delete.txt | xargs sudo apt purge -y
10

An update to @alex Burdusel's script would be the following:

#!/bin/bash -e
# Run this script without any arguments for a dry run
# Run the script with root and with exec arguments for removing old kernels and modules after checking
# the list printed in the dry run

uname -a IN_USE=$(uname -a | awk '{ print $3 }') echo "Your in use kernel is $IN_USE"

OLD_KERNELS=$( dpkg --get-selections | grep -v "linux-headers-generic" | grep -v "linux-image-generic" | grep -v "linux-image-generic" | grep -v "${IN_USE%%-generic}" | grep -Ei 'linux-image|linux-headers|linux-modules' | awk '{ print $1 }' ) echo "Old Kernels to be removed:" echo "$OLD_KERNELS"

OLD_MODULES=$( ls /lib/modules | grep -v "${IN_USE%%-generic}" | grep -v "${IN_USE}" ) echo "Old Modules to be removed:" echo "$OLD_MODULES"

if [ "$1" == "exec" ]; then apt-get purge $OLD_KERNELS for module in $OLD_MODULES ; do rm -rf /lib/modules/$module/ done fi

This solves the issue that it tries to delete the following packages:

linux-headers-generic
linux-image-generic
linux-headers-5.17.5-76051705 # if 5.17.5-76051705-generic is the current kernel

This script was modified to purge all packages at once, and also delete any remaining module directories in /lib/modules/

eitch
  • 373
  • 3
  • 6
7

Just use this:

sudo apt-get autoremove --purge
Ihor Romanyshyn
  • 114
  • 1
  • 4
  • 7
    Note that this command won't remove older kernels only, but any package that is not needed as a dependency of other packages along with its configuration files. – BeastOfCaerbannog Jan 08 '21 at 12:07
  • @BeastOfCaerbannog, sure, thanks for the clarification. – Ihor Romanyshyn Jan 11 '21 at 10:24
  • 16
    It doesn't work for 20.04 (upgraded from 18.04, and upgraded from 16.04). I can list the packages, but ubuntu doesn't autoremove old kernels. – gavioto Jan 12 '21 at 17:31
  • 1
    @gavioto20 strange, I also used Ubuntu 20.04 and this command did work for removing old kernels? It will only remove kernels that are not actively used. – Melroy van den Berg Mar 29 '22 at 16:39
  • FWIW, I was trying to run this command after installing a new kernel had failed because I was running out of space on /boot. Unfortunately, the command tried installing the new kernel again which… failed again – probably because it hadn't finished removing all those old images yet. :/ Ultimately I went with @eitch's script and this worked like a charm. – balu Sep 11 '23 at 10:14
5

To easily remove older versions kernels, e.g. kernels starting from 4.0 and so on.

sudo apt-get purge linux-image-4.*
Eliah Kagan
  • 117,780
  • Are you sure, that linux-image-4.* will remove "old" linux-image-5.4.xxx kernel images? – Simon Sudler Aug 30 '20 at 09:34
  • 3
    Ofcourse not, how do you expect that to remove kernels with a starting 5. You can update command accordingly. I just gave an example. For linux-image-5.4.xxx use sudo apt-get purge linux-image-5.4.* and so on. – shivam singh Sep 04 '20 at 07:14
  • You also have to do it for the headers: sudo apt purge linux-headers-4.* – Damien Dec 01 '22 at 14:46
1

autoremove will only remove packages that are automatically installed. If you ever updated or added a kernel package manually autoremove will not remove it. If you ever "held" a kernel version autoremove will not remove it. If you're wondering why Ubuntu is filling up your boot partition with kernels you no longer use it's likely one of these two reasons.

# Unhold all packages
dpkg --get-selections | grep hold | awk '{ print $1, "install" }' | dpkg --set-selections

Mark all "manually installed" kernel packages as "automatically installed"

for f in $(apt-mark showmanual | grep linux-); do apt-mark auto $f done

Remove all packages that are no longer needed

apt-get -y autoremove --purge

Earl Ruby
  • 735
1

I derived this script from previous answers. It should reserve the current kernel and one previous kernel. As stated in previous answers, execute once without any arguments for a dry run. Then run as root with 1 argument as 'exec' to actually remove the old kernels.

#!/bin/bash -e

IN_USE=$(uname -a | awk '{ print $3 }') echo "Your in use kernel is $IN_USE"

CUR_KERNELS=$(dpkg --get-selections | grep linux-image | grep install | awk '{print $1}') echo echo "Current Kernels are:" echo "$CUR_KERNELS"

OLD_KERNELS=$(dpkg --get-selections | grep linux | grep deinstall | awk '{print $1}') echo echo "Old Kernels to be removed:" echo "$OLD_KERNELS"

if [ "$1" == "exec" ]; then apt-get purge $OLD_KERNELS fi

0

As for easy solution, use a utility called linux-purge that is made just for the purpose, and that is supposed to work by any release of Ubuntu later than 12.04. The utility is implemented using Bash.

Here is my answer with more details to another similar question.

jarno
  • 5,600
0

Further improvement to the script:

Courtesy of @eitch

This version filters out the newer kernels. In earlier versions, the newer kernels will also get purged.

This script defaults to "dry-run" but if the $1 is anything other than "dry-run" or "exec" then the usage help text is displayed.

#!/bin/bash -e

Function to print usage instructions

print_usage() { echo "Usage: $0 [dry-run|exec]" echo " dry-run: List old kernels and modules without removing them (default)" echo " exec: Remove the listed old kernels and modules (requires root privileges)" }

Function to compare kernel version numbers

Returns 1 if version1 is greater than version2, 0 if equal, and -1 if lesser

compare_versions() { local version1=(${1//./ }) local version2=(${2//./ })

for i in {0..2}; do if [[ ${version1[i]} -gt ${version2[i]} ]]; then return 1 elif [[ ${version1[i]} -lt ${version2[i]} ]]; then return -1 fi done

return 0 }

Check for valid input arguments

if [[ $# -gt 1 ]] || { [[ $# -eq 1 ]] && [[ "$1" != "dry-run" ]] && [[ "$1" != "exec" ]]; }; then print_usage exit 1 fi

Display current running kernel

uname -a IN_USE=$(uname -a | awk '{ print $3 }') echo "Your in-use kernel is $IN_USE"

Find old kernels

OLD_KERNELS=$( dpkg --get-selections | grep -v "linux-headers-generic" | grep -v "linux-image-generic" | grep -Ei 'linux-image|linux-headers|linux-modules' | awk '{ print $1 }' | grep -v "${IN_USE}" )

Filter out newer kernels

FILTERED_KERNELS="" for kernel in $OLD_KERNELS; do kernel_version=$(echo "$kernel" | grep -oP '(?<=linux-image-|linux-headers-|linux-modules-)[0-9]+(.[0-9]+){0,2}' || true) if [[ ! -z "$kernel_version" ]]; then compare_versions "$kernel_version" "$IN_USE" if [[ $? -eq -1 ]]; then FILTERED_KERNELS+="$kernel"$'\n' fi else FILTERED_KERNELS+="$kernel"$'\n' fi done OLD_KERNELS="$FILTERED_KERNELS"

Find old modules

OLD_MODULES=$( ls /lib/modules | grep -v "${IN_USE}" | while read -r module; do module_version=$(echo "$module" | grep -oP '[0-9]+(.[0-9]+){0,2}' || true) if [[ ! -z "$module_version" ]]; then compare_versions "$module_version" "$IN_USE" if [[ $? -eq -1 ]]; then echo "$module" fi else echo "$module" fi done )

Display old kernels and modules

echo "Old Kernels to be removed:" echo "$OLD_KERNELS" echo "Old Modules to be removed:" echo "$OLD_MODULES"

Remove old kernels and modules if "exec" argument is passed

if [ "$1" == "exec" ]; then

Check for root privileges

if [ "$(id -u)" != "0" ]; then echo "Error:This operation requires root privileges. Please run the script as root or use 'sudo'." exit 1 fi

Remove Old Kernel

apt-get purge $OLD_KERNELS

Remove Old Modules

for module in $OLD_MODULES ; do rm -rf /lib/modules/$module/ done fi

-2

Not one of these worked for me.

Had to use:

sudo dpkg --purge linux.modules-extra-5.4.0-84.94