63

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
  • 72,312

12 Answers12

71

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
56

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
  • 34,024
  • 52
  • 172
  • 299
Alex Burdusel
  • 1,663
  • 2
  • 18
  • 25
27

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
12

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
  • 403
9

Just use this:

sudo apt-get autoremove --purge
6

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
  • 119,640
3

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
  • 841
2

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

1

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
  • 6,175
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

0

The update manager allows you to delete old headers with the UI. I tried this with the Ubuntu-based Linux Mint:

  • Launch Update Manager
  • Select View | Linux Kernels
  • You'll see a list of installed kernels:

enter image description here

  • You can remove them individually, or (even better)
  • Select Remove Kernels...

enter image description here

  • Adjust the selection as you see fit, although the recommended selection is usually what you want.
  • Voila, you're done!
jastram
  • 283
-2

Not one of these worked for me.

Had to use:

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