Remove Old Kernels In Ubuntu With One Command

October 2, 2010 by
Filed under: command line, HowTo, linux, Ubuntu 

A while back I wrote a post on how to remove old kernels from your Ubuntu system. While that process works just fine, it is a four step process. One person who read that post left a comment with a nice command line one-liner that removes all but the currently running kernel. And while that one-liner works quite well, I must admit that I don't understand all the regular expressions used in it, so I decided to try and come up with my own one-liner to remove the old kernels from my system.

I'm going to take you through this step by step so you can see how the individual commands in this one-liner tie together. If you're impatient, you can skip to the end to see the final command.

Step 1) List all packages that start with "linux-"

We'll use the dpkg command with the -l switch to list the packages, whether installed or not, that start with the string linux-.

dpkg -l linux-*

Step 2) Filter that list to show only installed packages

To filter the list, I'm going to pipeline the output of the first command into the awk command. I'm also going to use awk to filter out everything but the package names.

Affiliate Link
dpkg -l linux-* | awk '/^ii/{ print $2 }'

Step 3) Filter out packages for the currently running kernel

OK, so now I'm down to a pretty limited number of packages, but I don't want to remove the packages for my currently running kernel. I'm going to use a few commands to do that. First off, I can determine my currently running kernel with the uname -r command. Currently on my system that command outputs: 2.6.32-25-generic.

To do my package filtering, I only want the numeric portion of that output. I'll pipeline the output of uname -r and use the cut command with a hyphen as the field delimiter. I'll cut fields 1 & 2.

uname -r | cut -f1,2 -d"-"

Now I'm going to use this result as the filter for a grep command. In Linux, to use the result of one command as an argument in another command, you enclose the command in single back-quotes ( ` that's the key to the left of the 1 on a standard US keyboard). So here's my one-liner so far.

dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -v -e `uname -r | cut -f1,2 -d"-"`

This is the output so far on my system:

linux-firmware
linux-generic
linux-headers-2.6.32-24
linux-headers-2.6.32-24-generic
linux-headers-generic
linux-image-2.6.32-24-generic
linux-image-generic
linux-libc-dev
linux-sound-base

Step 4) Filter the list for only the kernel packages

So now I have a package list that excludes the packages for my current kernel. The only packages from the list above that I want to remove are: linux-headers-2.6.32-24, linux-headers-2.6.32-24-generic, linux-image-2.6.32-24-generic.

What makes these packages unique from the others in the list is that they all contain numbers. So I can use grep again to filter the list down to only packages with numbers in their names. I'll pipeline the output of the previous command into grep -e [0-9].

dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -v -e `uname -r | cut -f1,2 -d"-"` | grep -e [0-9]

So now the output on my system is only the following:

linux-headers-2.6.32-24
linux-headers-2.6.32-24-generic
linux-image-2.6.32-24-generic

Step 5) Make sure we don't catch any stray packages

Some people have had problems with this one-liner catching the linux-libc-dev:amd64 package. Adding a

grep -E "(image|headers)"

to the string fixes the problem. Now we have

dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -v -e `uname -r | cut -f1,2 -d"-"` | grep -e [0-9] | grep -E "(image|headers)"

Step 6) Putting it all together: Removing the packages

So now that I have a good list of packages I can use another pipe and the xargs command to invoke apt-get to remove the packages. First I'm going to show it using the --dry-run switch with apt-get. That way you can give it a try without actually changing your system.

dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -v -e `uname -r | cut -f1,2 -d"-"` | grep -e [0-9] | grep -E "(image|headers)" | xargs sudo apt-get --dry-run remove

If everything looks good after the dry run, you can go ahead and remove the old kernels with:

dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -v -e `uname -r | cut -f1,2 -d"-"` | grep -e [0-9] | grep -E "(image|headers)" | xargs sudo apt-get -y purge

So there you have it. One command, albeit a long one, to remove the old kernels from your Ubuntu system. I imagine the same command should work on other Debian based systems as well, but I've only tested this on my 32 bit system. I'd be interested to know if it works just as well on a 64 bit system.

Update: It works just fine on 64 bit systems as well.

Comments

80 Responses to “Remove Old Kernels In Ubuntu With One Command”

  1. martini says:

    Why not just

    $sudo apt-get autoremove

    ?

  2. kimme says:

    I use this script to clear my kernels


    #/bin/bash
    ls /boot/ | grep vmlinuz | sed 's@vmlinuz-@linux-image-@g' | grep -v `uname -r` > /tmp/kernelList
    for I in `cat /tmp/kernelList`
    do
    aptitude remove $I
    done
    rm -f /tmp/kernelList
    update-grub

  3. bettyfurness says:

    superboer12 - great command, worked fine on my 64 bit Lucid. How would I modify this script to keep the last two kernels? I had .39, .40 and .41. After running this I had only .41. Booted OK but I always worry.

    Thanks!

  4. fintux says:

    Thanks, this made my life alot easier! :)

  5. EriK says:

    Thanks worked a treat!

  6. kiwinut says:

    Hi all ... thank you for the nice command ... I have just run it on my Ubuntu Lucid 64 bit and it worked perfectly ... :-)

  7. MJ says:

    i'v been updating for almost 2 years now.. this freed 2.7 GB of storage.. THANKS

  8. Ubuntu Server says:

    Worked perfectly for me.
    After I finished, I ran /usr/sbin/update-grub just to be safe.

    Matt Locke - Nashville, TN

  9. superboer12 says:

    I modified it a little bit to keep both the running and the newest kernel.
    Thanks for the script!
    [code]
    rmkernel () {
    local cur_kernel=$(uname -r|sed 's/-*[a-z]//g'|sed 's/-386//g')
    local kernel_pkg="linux-(image|headers|ubuntu-modules|restricted-modules)"
    local meta_pkg="${kernel_pkg}-(generic|i386|server|common|rt|xen|ec2|amd64)"
    local pre_kernel=$(echo ${cur_kernel} | tr '' \\\n | awk 'BEGIN{FS="-";OFS="-"} {print $1,$2-1}')
    local latest_kernel=$(dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -v -e `uname -r | cut -f1,2 -d"-"` | grep -e [0-9] | tail -1 | cut -f3,4 -d"-")
    aptitude purge -y $(dpkg -l | egrep $kernel_pkg | egrep -v "${cur_kernel}|${meta_pkg}|${latest_kernel}" | awk '{print $2}')
    }

    rmkernel

    exit 0
    [/code]

    • superboer12 says:

      Little correction:


      #!/bin/bash

      rmkernel () {
      local cur_kernel=$(uname -r|sed 's/-*[a-z]//g'|sed 's/-386//g')
      local kernel_pkg="linux-(image|headers|ubuntu-modules|restricted-modules)"
      local meta_pkg="${kernel_pkg}-(generic|i386|virtual|server|common|rt|xen|ec2|amd64)"
      local latest_kernel=$(dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -e [0-9] | tail -1 | cut -f3,4 -d"-")
      aptitude purge -y $(dpkg -l | egrep $kernel_pkg | egrep -v "${cur_kernel}|${meta_pkg}|${latest_kernel}" | awk '{print $2}')
      }

      rmkernel

      exit 0

  10. Cesare says:

    Thank you!!! It worked like a charm.

  11. Warfie says:

    That's rather more than one command. LOL

  12. R E Broadley says:

    Very nice, but this article seems to assume that you're already running the OS with the latest kernel, so as this article goes, it will delete all kernels except the one currently running, which may be an old one.

    What would be a better command is if it deleted all kernels except the latest one (and perhaps also the one currently running).

    Speaking of which, why doesn't ubuntu default to running the latest one? Despite installing kernel updates, mine's still defaulting to an old one...

  13. Santanu says:

    It's always a good idea to keep the last kernel installed. So, I'd modify the rmkernel script to add this line for the previous version of kernel:
    [code]local pre_kernel=$(echo ${cur_kernel} | tr '' \\\n | awk 'BEGIN{FS="-";OFS="-"} {print $1,$2-1}')[/code]
    and then add pre_kerne to the exclude list:
    [code]sudo aptitude purge $(dpkg -l | egrep $kernel_pkg | egrep -v "${cur_kernel}|${pre_kernel}|${meta_pkg}" | awk '{print $2}'[/code]

    For the one-liner:
    [code]dpkg -l linux-* | awk '/^ii/{ print $2}' | grep -v -e `uname -r | cut -f1,2 -d"-"` -e `uname -r | gawk 'BEGIN{FS="-";OFS="-"} {print $1,$2-1}'` | grep -e [0-9][/code]

    Cheers!!

  14. K says:

    Thanks for the handy script.
    I had to add -y argument to apt-get to make it work. Ubuntu 10.10.

  15. DKlann says:

    To take it one step further, you can purge all the old configuration files with the following (after completing the Big One Liner (above):

    dpkg -l 'linux-*' | awk '/^rc/{ print $2}' | sudo xargs apt-get -y purge

    Thanks for this nice little ditty!

    Does anyone know how (or whether it makes sense) to delay the execution of the postrm.d scripts until after all the pieces are removed? It gets a little tiresome watching all those initramfs and zz-update-grub calls...

    • Linerd says:

      Thanks for the tip. I didn't know those rc status config files were still hanging around. However, when I try your command I get this type of error:

      Package linux-image-2.6.32-27-generic is not installed, so not removed

      When I modify your command to:

      dpkg -l 'linux-*' | awk '/^rc/{ print $2}' | sudo xargs dpkg --purge

      it works.

      After doing some research, it looks like if I change my one-liner to purge instead of remove, then it should get rid of the config files as well and make this all moot, so I'm updating my post. I'll install an older kernel and re-run the command to see if it works.

    • Linerd says:

      OK, I verified that changing my one-liner to purge instead of remove resolves the config file issue.

  16. David says:

    Thanks it worked great.

  17. RJ says:

    it works with 64-bit. thanks

  18. Vern says:

    "I'd be interested to know if it works just as well on a 64 bit system"
    Testing on Ubuntu Lucid amd64 system, and it works.

    Also someone posted this at Ubuntu forums a while back as a function script that works well:

    rmkernel () {
            local cur_kernel=$(uname -r|sed 's/-*[a-z]//g'|sed 's/-386//g')
            local kernel_pkg="linux-(image|headers|ubuntu-modules|restricted-modules)"
            local meta_pkg="${kernel_pkg}-(generic|i386|server|common|rt|xen|ec2)"
            sudo aptitude purge $(dpkg -l | egrep $kernel_pkg | egrep -v "${cur_kernel}|${meta_pkg}" | awk '{print $2}')
    }
    
    rmkernel
    
    exit 0
    
  19. carl801 says:

    Hey, it works. Had to run update-grub, then because I'm using BURG, had to run update-burg. There oughta be a button somewhere for this command, eh?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>