21

While browsing the internet for Ubuntu articles, I came across this command:

sudo dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge

The author said that this is a single line command which will delete all the previous versions of Linux, leaving only the current one!

I'm actually looking for such a command, but I'm not so sure on how safe this is. I'd like to know:

  • Whether it is safe to execute this command?
  • How does this command work? i.e. explanation of small parts of such a big command
  • If this command serves some different purpose, then what would be the correct command to achieve what the author claims it to do?

I become very confused and frustrated when I try to infer out all by myself. How does this command work for it contains numerous /, |, \, *, and ^ characters which are hard to Google for.

I am looking for a step by step translation & explanation for this command which I was unable to find across the internet!

4
  • 1
    This does not seem to be the same command you quote, but I have been using the command in tuxtweaks.com/2010/10/… to remove old kernels without any issues. This page also explains what the command does.
    – user68186
    Jan 18, 2013 at 18:36
  • 4
    @UriHerrera apt-get autoremove doesn't suggest any removals of older kernels for me. If I don't delete them, they'll just pile up till my /boot is out of space and updates fail. Do you have a reference for it about that it should do this?
    – gertvdijk
    Jan 18, 2013 at 21:46
  • 1
    It does for me, whenever there's a new update for the kernel, it says afterwards the following packages etc, are no longer required and it lists the previous kernel that I had. Jan 18, 2013 at 21:59
  • My answer was deleted by a moderator, so I comment here: See this article for explanation of the script. I don't see why one part of the script is s/^[^ ]* [^ ]* \([^ ]*\).*/\1/ instead of simply s/^[^ ]* \([^ ]*\).*/\1/. The script is not very robust or elegant. For example why check for current kernel before extracting the package name from the output? As for an alternative, sudo apt-get autoremove --purge purges most old kernels in some latest release of Ubuntu like Xubuntu 15.10.
    – jarno
    Dec 24, 2015 at 1:32

4 Answers 4

28

I'd say: don't use it in the current form

  1. It makes changes without asking you. The apt-get -y purge part allows the one-liner to start executing purging packages, without your confirmation. If any error in the script exists, then you could be screwed.

  2. No source, no author given. The source of it makes a difference here. In case it would come from a thoroughly tested system package we can trace the testing being done onto it. From a random source, we can't trust it.

  3. dpkg -l runs fine without sudo. I don't see why the original author thought this was necessary.

Use common sense

Remove the harmful parts and leave out anything that runs as root.

For example, cut it down to this:

dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'

which just only outputs stuff and runs with regular user permissions. Once you agree with these kernels to be removed, you can append | xargs sudo apt-get purge yourself. It's without the -y option, intentionally, so you'll be asked for confirmation on the changes about to be made to your system.

Explanation

  • dpkg -l Outputs the list of all packages. In this case it will only list packages starting with linux- as the name.
  • | (a pipe) pipes the output of the command on the left (we call that stdout) to the input of the command on the right (we call that stdin).
  • sed is a tool to manipulate strings using regular expressions. In this case it manipulates the output of the command on the left of the pipe and filters for installed packages (relying on the ii as given by dpkg). It is even being nested in this case. It would be too hard to explain the whole use of sed here, as its use is very complicated with the complex regular expressions. (the \(.*\)-\([^0-9]\+\)" is an example of a regular expression.
  • Regular expressions are very widely used to find matches based on the expression they represent. \1 is the replacement reference to do a sort of universal search-and-replace (referencing to the first 'hit' with 1). The regular expression themselves can't do any harm. However, if they manipulate the input in a wrong way, they can have you remove the wrong packages or even do shell injection. In this case it looks like a way to find the name of the kernel package based on the version provided by uname -r.
  • uname -r outputs the current version of the kernel running.
  • xargs appends the lines of the input left of the pipe as arguments to the command. In this case, the kernel versions on each line are converted to a horizontal space-separated list and appended to the sudo apt-get command.
  • sudo apt-get -y purge [packagename] purges (removes everything) of the packages given (as arguments).

Alternatives

Quite some question are probably already asked about this. Relevant ones I found so far:

5
  • 1
    what shall be the breakup of the scary looking node of this command which is something like this /(.*)-([^0-9]\+)/\1/")"'/d;s/^[^ ]* [^ ]* ([^ ]*).*/\1/;/ Jan 18, 2013 at 18:44
  • will the above said command in this answer clear old kernels gracefully ?? or still apt-get autoremove is better ?? Jan 18, 2013 at 18:45
  • 4
    @Z9iT Those are regular expressions. They're used to find matches based on the expression they represent and the \1 is the replacement control to do a sort of universal search-and-replace. For removal of any package I've expressed myself clear in my answer (being my opinion): use common sense. Don't let a script do changes to your system automatically. Verify what it would do. Always.
    – gertvdijk
    Jan 18, 2013 at 18:50
  • The alternative you feature does not purge respective linux-header packages.
    – jarno
    Dec 23, 2015 at 11:29
  • Then just do an apt-get autoremove, which should detect those headers are no longer needed. Sep 19, 2017 at 15:50
7

You asked for a step-by-step explanation so here goes:

sudo dpkg -l 'linux-*'

Lists packages starting with linux- in the package name

| sed

and pipe the list into sed

"s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'

which will use a very complicated regular expression to edit the list

| xargs

which will pipe the new list into xargs, which will send it as an argument to

sudo apt-get -y purge

which will purge those packages without giving you a chance to change your mind.

Or perhaps it's more accurate to say it will send that list into the purge command and leave it at that. Whether or not anything is purged — and importantly — exactly what is purged depends on the ouput of the previous commands.

Is it safe? In this case that all depends on how well the author of the post where you found it understands regular expressions and sed syntax. And there are whole books on both of those topics.

6

I started by dissecting the commands, reading the man page for each.

  • dpkg -l: list pacakges, so dpkg -l linux-* would list all packages that started with linux- (usually kernels).

  • sed: The output of dpkg -l linux-* is piped to sed with several regular expressions which sed decodes.

  • uname -r unameprints system information

uname - print system information

The -r handle specifically prints kernel releases:

-r, --kernel-release print the kernel release

The output of uname -r is then piped to sed with more regular expressions, the output of which is passed to xargs

So xargs translates the sed output into package names and passes them onto sudo apt-get purge -y which automatically answers 'yes' to all prompts:

-y, --yes, --assume-yes Automatic yes to prompts; assume "yes" as answer to all prompts and run non-interactively. If an undesirable situation, such as changing a held package, trying to install a unauthenticated package or removing an essential package occurs then apt-get will abort. Configuration Item: APT::Get::Assume-Yes.

Altogether it seems this command will do what you want, though to know for sure we'd have to translate sed's regular expressions.

I just ran:

dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'  

here is a screenshot:

enter image description here

All old kernel versions iirc.

7
  • what's the workout to translate this sed's expression ? Jan 18, 2013 at 18:55
  • 2
    I'm trying to understand it right now, might take we a while ;)
    – Seth
    Jan 18, 2013 at 19:00
  • See my answer.
    – jarno
    Dec 23, 2015 at 11:33
  • @Z9iT I was too lazy to copy the explanation of the script from the linked article to the answer, so I guess that is why Seth deleted my answer. But I think the linked article is what you were looking for from the Internet. I also told you a safer way to remove old kernels, though it keeps 2-3 kernels just in case, and may not work in all current Ubuntu releases yet.
    – jarno
    Dec 24, 2015 at 13:36
  • @jarno I deleted it because Z9iT was asking about a specific command, not a safe way to remove old kernels. That might still be relevant, but in a comment, not an answer :) (like you did)
    – Seth
    Dec 24, 2015 at 17:37
0

A less dangerous version of this script that removes unused and out of date kernels matches for rc in the beginning of a line of the dpkg output, instead of ii. (See https://askubuntu.com/a/18807/220802 for an explanation of these flags.) In my case this exactly matches all kernel packages which are not protected by /etc/apt/apt.conf.d/01autoremove-kernels.

For example:

# sed -n '/to keep/,$p' /etc/apt/apt.conf.d/01autoremove-kernels
# Kernel versions list to keep:
5.4.0-58.64
5.4.0-60.67
# Kernel packages (version part) to protect:
5\.4\.0-58-generic
5\.4\.0-60-generic
*/

and

# dpkg -l 'linux-*' | sed '/^rc/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'
linux-image-5.3.0-18-generic
linux-image-5.3.0-19-generic
linux-image-5.3.0-45-generic
linux-image-5.4.0-21-generic
linux-image-5.4.0-26-generic
linux-image-5.4.0-28-generic
linux-image-5.4.0-31-generic
linux-image-5.4.0-33-generic
linux-image-5.4.0-40-generic
linux-image-5.4.0-42-generic
linux-image-5.4.0-48-generic
linux-image-5.4.0-52-generic
linux-image-5.4.0-53-generic
linux-image-5.4.0-56-generic
linux-modules-5.3.0-18-generic
linux-modules-5.3.0-19-generic
linux-modules-5.3.0-45-generic
linux-modules-5.4.0-21-generic
linux-modules-5.4.0-26-generic
linux-modules-5.4.0-28-generic
linux-modules-5.4.0-31-generic
linux-modules-5.4.0-33-generic
linux-modules-5.4.0-40-generic
linux-modules-5.4.0-42-generic
linux-modules-5.4.0-48-generic
linux-modules-5.4.0-52-generic
linux-modules-5.4.0-53-generic
linux-modules-5.4.0-56-generic
linux-modules-extra-5.3.0-18-generic
linux-modules-extra-5.3.0-19-generic
linux-modules-extra-5.3.0-45-generic
linux-modules-extra-5.4.0-21-generic
linux-modules-extra-5.4.0-26-generic
linux-modules-extra-5.4.0-28-generic
linux-modules-extra-5.4.0-31-generic
linux-modules-extra-5.4.0-33-generic
linux-modules-extra-5.4.0-40-generic
linux-modules-extra-5.4.0-42-generic
linux-modules-extra-5.4.0-48-generic
linux-modules-extra-5.4.0-52-generic
linux-modules-extra-5.4.0-53-generic
linux-modules-extra-5.4.0-56-generic

which you can pipe to | xargs apt purge -y now. Please note that omitting the -y flag will result in abortion of the operation.

Then you can check your /boot directory for further remnants of older kernels. In my case there were more files hanging around that were not tracked by apt anymore, which were removed with ls /boot/*-5.4.0-{00..56}* 2>/dev/null being heartfully piped to | xargs rm -rf.

You must log in to answer this question.

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