当前位置: 首页>>技术教程>>正文


Bash one-liner 仅删除旧内核

, ,

问题描述

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

我需要 one-liner 的解决方案,因为我将从 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。

感谢您抽出宝贵时间,\n亚历杭德罗。

最佳回答

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

  1. 列出所有 linux-* 会得到很多误报,例如(来自我的输出的示例) linux-sound-base 。即使这些可能会在稍后被您的其余命令过滤掉,但我个人觉得不首先列出它们会更安全。更好地控制要删除的软件包。不要做可能会产生意想不到的结果的事情。所以我会从

    \n

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

    \n

     egrep '[0-9]+\\.[0-9]+\\.[0-9]+'\n
  3. 然后是这个排序的事情。为什么要排序?既然您无论如何都要删除所有内核(当前内核除外),那么在新内核之前删除旧内核对您来说重要吗?我不认为这有什么区别。还是您只是这样做,然后您可以使用 sed 来“仅打印当前内核之后的结果”?但是 IMO 这感觉太复杂了。为什么不简单地过滤掉与当前内核相对应的结果,就像您已经在使用 grep -v 所做的那样,然后完成呢?老实说,如果我接受你命令的第一部分(结合我之前的两个建议),我会在我的机器上得到

    \n

    $ 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"-"`\nlinux-image-3.8.0-34-generic\nlinux-image-3.5.0-44-generic\n

    \n

    删除排序/sed 的东西,我得到

    \n

    $ 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"-"`\nlinux-image-3.5.0-44-generic\nlinux-image-3.8.0-34-generic\nlinux-image-extra-3.5.0-44-generic\nlinux-image-extra-3.8.0-34-generic\n

    \n

    所以你更复杂的命令实际上会错过我机器上的两个包,我想删除(现在那些 linux-image-extra-* 东西可能依赖于 linux-image-* 东西,因此无论如何都会被删除,但让它明确不会有什么坏处)。无论如何,我看不出你排序的意义。一个没有花哨预处理的简单 grep -v 应该没问题,可能会更好。我是 KISS 原则的支持者。它将使您以后更容易理解或调试。此外,如果没有排序,它的效率会更高;)

  4. 这纯粹是美学,但您将使用这个稍短的变体获得相同的输出。 🙂

    \n

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

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

$ 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' | linux-version sort | 
awk '($1==c){exit} {print $2}' c=$(uname -r | cut -f1,2 -d-))

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

第三种回答

TL;DR:跳到底部。

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

  1. 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}' 所必需的结果是一个新列,其版本号位于原始包名称之前,如下所示:

    \n

    $ 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}'\n3.11.0-23 linux-headers-3.11.0-23\n3.11.0-23 linux-headers-3.11.0-23-generic\n3.11.0-24 linux-headers-3.11.0-24\n3.11.0-24 linux-headers-3.11.0-24-generic\n3.11.0-26 linux-headers-3.11.0-26\n3.11.0-26 linux-headers-3.11.0-26-generic\n3.11.0-23 linux-image-3.11.0-23-generic\n3.11.0-24 linux-image-3.11.0-24-generic\n3.11.0-26 linux-image-3.11.0-26-generic\n3.8.0-35 linux-image-3.8.0-35-generic\n3.11.0-23 linux-image-extra-3.11.0-23-generic\n3.11.0-24 linux-image-extra-3.11.0-24-generic\n3.11.0-26 linux-image-extra-3.11.0-26-generic\n3.8.0-35 linux-image-extra-3.8.0-35-generic\n
  4. 现在我们必须对列表进行排序,以防止卸载任何比当前运行的图像更新的图像。 sort -k1,1 --version-sort -r 给我们这个:

    \n

    $ 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\n3.11.0-26 linux-image-extra-3.11.0-26-generic\n3.11.0-26 linux-image-3.11.0-26-generic\n3.11.0-26 linux-headers-3.11.0-26-generic\n3.11.0-26 linux-headers-3.11.0-26\n3.11.0-24 linux-image-extra-3.11.0-24-generic\n3.11.0-24 linux-image-3.11.0-24-generic\n3.11.0-24 linux-headers-3.11.0-24-generic\n3.11.0-24 linux-headers-3.11.0-24\n3.11.0-23 linux-image-extra-3.11.0-23-generic\n3.11.0-23 linux-image-3.11.0-23-generic\n3.11.0-23 linux-headers-3.11.0-23-generic\n3.11.0-23 linux-headers-3.11.0-23\n3.8.0-35 linux-image-extra-3.8.0-35-generic\n3.8.0-35 linux-image-3.8.0-35-generic\n
  5. 现在去掉当前和更新的内核文件 sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` 给我们这个:

    \n

    $ 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"-"`\n3.11.0-23 linux-image-extra-3.11.0-23-generic\n3.11.0-23 linux-image-3.11.0-23-generic\n3.11.0-23 linux-headers-3.11.0-23-generic\n3.11.0-23 linux-headers-3.11.0-23\n3.8.0-35 linux-image-extra-3.8.0-35-generic\n3.8.0-35 linux-image-3.8.0-35-generic\n
  6. 现在去掉我们用 awk '{print $2}' 添加的第一列,得到我们想要的:

    \n

    $ 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}'\nlinux-image-extra-3.11.0-23-generic\nlinux-image-3.11.0-23-generic\nlinux-headers-3.11.0-23-generic\nlinux-headers-3.11.0-23\nlinux-image-extra-3.8.0-35-generic\nlinux-image-3.8.0-35-generic\n
  7. 现在我们可以将它提供给包管理器以自动删除所有内容并重新配置 grub:

    \n

    我建议先进行一次试运行(尽管对于您的脚本而言,如果您有一个大型环境,这可能不切实际)

    \n

    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\n

    \n

    现在,如果一切看起来都不错,请使用以下命令实际删除它:

    \n

    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\n

再一次,这个 “one-liner” 的重点是只删除比当前运行的内核更旧的内核(这使得任何新安装的内核仍然可用)

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

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/13055.html,未经允许,请勿转载。