Bash one-liner只删除旧内核

我已经看到很多关于如何在/ boot分区上释放空间的线程,这也是我的目标。 但是,我只对删除内核感兴趣,而不是删除现有内核中的每一个内核。

我需要解决方案是一个单行,因为我将从Puppet运行脚本,我不希望有额外的文件。 到目前为止,我得到以下内容:

dpkg -l linux-* | awk '/^ii/{print $2}' | egrep [0-9] | sort -t- -k3,4 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | xargs sudo apt-get -y purge 

更确切地说,它目前的作用如下:

  • 列出所有linux- *包并打印他们的名字。
  • 仅列出具有数字并对其进行排序的那些,返回相反的结果。 这样,旧内核最后列出。
  • 仅打印当前内核之后的结果
  • 由于有一些linux- {image,headers}结果,请确保我不会清除与当前内核相关的任何内容
  • 打电话给清洗

这很有效,但我确信解决方案可以更加优雅,并且对于生产环境来说是安全的,因为我们的服务器中至少有20个运行Ubuntu。

谢谢你的时间,亚历杭德罗。

看起来不错,只是一些评论。 两个第一个注释使命令更安全,而第三个和第四个注释使它更短。 随意关注或忽略其中任何一个。 虽然我强烈建议你遵循前两个。 你想确保它尽可能安全。 我的意思是认真。 你在一些自动生成的包列表中抛出一个sudo apt-get -y purge 。 那太邪恶了 ! 🙂

  1. 列出所有linux-*会得到许多误报,例如(我的输出示例) linux-sound-base 。 尽管这些可能会在以后的命令中被过滤掉,但我个人觉得更安全而不是首先列出它们。 更好地控制要删除的包。 不要做可能产生意外结果的事情。 所以我会开始

     dpkg -l linux-{image,headers}-* 
  2. 在我看来,你的“只列出有数字的那个”的正则表达式有点过于简单了。 例如,当你在64位系统上时,有一个包linux-libc-dev:amd64 。 你的正则表达式会匹配。 你不希望它匹配。 不可否认,如果您遵循我的第一个建议,那么无论如何linux-libc-dev:amd64都不会被列出,但仍然如此。 我们更多地了解版本号的结构而不是简单的事实“有一个数字”。 另外,引用正则表达式通常是一个好主意,只是为了防止shell可能出现误解。 所以我会做那个egrep命令

      egrep '[0-9]+\.[0-9]+\.[0-9]+' 
  3. 然后有这种分类的东西。 你为什么要排序? 既然你要删除所有的内核(当前的内核除外),那么在较新的内核之前删除较旧的内核是否重要? 我认为它没有任何区别。 或者你只是这样做,所以你可以使用sed “仅打印当前内核之后的结果”? 但IMO感觉太复杂了。 为什么不简单地过滤出与当前内核相对应的结果,就像你已经使用grep -v ,并且完成了? 老实说,如果我采取你的命令的第一部分(我的两个以前的建议集成),我得到了我的机器

     $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | sort -t- -k3,4 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` linux-image-3.8.0-34-generic linux-image-3.5.0-44-generic 

    删除那些排序/ sed的东西,我明白了

     $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | grep -v -e `uname -r | cut -f1,2 -d"-"` linux-image-3.5.0-44-generic linux-image-3.8.0-34-generic linux-image-extra-3.5.0-44-generic linux-image-extra-3.8.0-34-generic 

    所以你的更复杂的命令实际上会错过我的机器上的两个软件包,我想要删除(现在这些linux-image-extra-* thingys可能依赖于linux-image-* thingys,因此无论如何都会被删除,但是要明确表达它并不会有害。 无论如何,我没有看到你的分类; 一个简单的grep -v没有花哨的预处理应该没问题,大概更好。 我是KISS原则的支持者。 它将使您以后更容易理解或调试。 此外,没有排序它会更有效;)

  4. 这纯粹是aestethic,但你会得到相同的输出与这个稍短的变体。 🙂

     $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | grep -v $(uname -r | cut -d- -f-2) linux-image-3.5.0-44-generic linux-image-3.8.0-34-generic linux-image-extra-3.5.0-44-generic linux-image-extra-3.8.0-34-generic 

因此,我最终得到了更简单,更安全的命令

 $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | grep -v $(uname -r | cut -d- -f-2) | xargs sudo apt-get -y purge 

由于您实际上想要清理/boot分区,一种完全不同的方法是列出/boot的内容,使用dpkg -S来确定各个文件所属的包,过滤掉属于当前内核的包,并删除生成的包。 但我更喜欢你的方法,因为它也会发现过时的软件包,例如linux-headers-* ,它们没有安装到/boot ,而是安装到/usr/src

我编写了这个脚本,删除了版本比当前启动的版本少的“linux- *”软件包。 我认为没有必要测试包状态。 该命令在清除包之前要求确认。 如果您不想这样,请在apt-get命令中添加-y选项。

 sudo apt-get purge $(dpkg-query -W -f'${Package}\n' 'linux-*' | sed -nr 's/.*-([0-9]+(\.[0-9]+){2}-[^-]+).*/\1 &/p' | sort -k 1,1V | awk '($1==c){exit} {print $2}' c=$(uname -r | cut -f1,2 -d-)) 

但是,为了能够保留可配置数量的备用内核,我建议使用带有--keep选项的linux-purge脚本。 有关脚本的更多信息,请参见此处 。

TL; DR:跳到底部。

虽然它有点长。 我会为你分解一下:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'就像Malte建议的那样。 列出相关的内核文件。
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Malte还建议通过查找版本号来选择仅内核文件的更安全的方法。
  3. 由于我们现在可能列出图像和标题包,因此包命名可能会有所不同,所以我们有这个awk解决方法,这对于排序awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'结果是一个新列,其原始包名前的版本号如下:

     $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' 3.11.0-23 linux-headers-3.11.0-23 3.11.0-23 linux-headers-3.11.0-23-generic 3.11.0-24 linux-headers-3.11.0-24 3.11.0-24 linux-headers-3.11.0-24-generic 3.11.0-26 linux-headers-3.11.0-26 3.11.0-26 linux-headers-3.11.0-26-generic 3.11.0-23 linux-image-3.11.0-23-generic 3.11.0-24 linux-image-3.11.0-24-generic 3.11.0-26 linux-image-3.11.0-26-generic 3.8.0-35 linux-image-3.8.0-35-generic 3.11.0-23 linux-image-extra-3.11.0-23-generic 3.11.0-24 linux-image-extra-3.11.0-24-generic 3.11.0-26 linux-image-extra-3.11.0-26-generic 3.8.0-35 linux-image-extra-3.8.0-35-generic 
  4. 现在我们必须对列表进行排序,以防止卸载任何比当前正在运行的图像更新的图像。 sort -k1,1 --version-sort -r给我们这个:

     $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r 3.11.0-26 linux-image-extra-3.11.0-26-generic 3.11.0-26 linux-image-3.11.0-26-generic 3.11.0-26 linux-headers-3.11.0-26-generic 3.11.0-26 linux-headers-3.11.0-26 3.11.0-24 linux-image-extra-3.11.0-24-generic 3.11.0-24 linux-image-3.11.0-24-generic 3.11.0-24 linux-headers-3.11.0-24-generic 3.11.0-24 linux-headers-3.11.0-24 3.11.0-23 linux-image-extra-3.11.0-23-generic 3.11.0-23 linux-image-3.11.0-23-generic 3.11.0-23 linux-headers-3.11.0-23-generic 3.11.0-23 linux-headers-3.11.0-23 3.8.0-35 linux-image-extra-3.8.0-35-generic 3.8.0-35 linux-image-3.8.0-35-generic 
  5. 现在删除当前和更新的内核文件sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`给我们这个:

     $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` 3.11.0-23 linux-image-extra-3.11.0-23-generic 3.11.0-23 linux-image-3.11.0-23-generic 3.11.0-23 linux-headers-3.11.0-23-generic 3.11.0-23 linux-headers-3.11.0-23 3.8.0-35 linux-image-extra-3.8.0-35-generic 3.8.0-35 linux-image-3.8.0-35-generic 
  6. 现在剥离我们使用awk '{print $2}'添加的第一列,以获得我们想要的内容:

     $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | awk '{print $2}' linux-image-extra-3.11.0-23-generic linux-image-3.11.0-23-generic linux-headers-3.11.0-23-generic linux-headers-3.11.0-23 linux-image-extra-3.8.0-35-generic linux-image-3.8.0-35-generic 
  7. 现在我们可以将它提供给包管理器以自动删除所有内容并重新配置grub:

    我建议先做一个干运行(虽然为了你的脚本目的,如果你有一个大的环境,这可能不实用)

     dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | awk '{print $2}' | xargs sudo apt-get --dry-run remove 

    现在如果一切看起来都很好继续实际删除它:

     dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | awk '{print $2}' | xargs sudo apt-get -y purge 

再一次,这个“单线程”的重点是仅删除内核OLDER而不是当前运行的内核(这使得任何新安装的内核仍然可用)

谢谢让我知道这对你有用,如果你能改进它!

您可以使用’ls’命令简单地列出/ boot目录以查看您拥有的内核版本。 然后使用’sudo apt-get -y purge“xxx”’,其中“xxx”将替换为您要删除的版本号。 请注意,它不是您当前运行的版本!!

安装bikeshedapt install bikeshed )并以root身份调用purge-old-kernels

 $ sudo purge-old-kernels 

快速回答,根据要求解释:

 dpkg -l 'linux-image-[0-9]*' | awk -v current="$(uname -r)" '!/^i/ || $2~current {next} {print $2}' | sed '$d' | xargs echo sudo apt-get autoremove 

我真的厌倦了所有这些不必要的复杂性,并创建了一个Python包,使得单行简单:

 ubuntu-old-kernel-cleanup | xargs sudo apt-get -y purge 

安装它

 sudo pip install git+http://github.com/mrts/ubuntu-old-kernel-cleanup.git 

有关详细信息,请访问https://github.com/mrts/ubuntu-old-kernel-cleanup 。

希望这也有助于其他人。

 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 

一直工作,甚至ubuntu 17.10