Bash一线仅删除旧内核


23

我已经看到了很多关于如何释放/ 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。

谢谢您的宝贵时间,Alejandro。



如果单行代码未保存在脚本文件中,该如何使用?
jarno 2015年

Answers:


25

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

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

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

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
  3. 然后是这种分类的东西。你为什么排序?由于您仍然要删除所有内核(当前内核除外),因此对您来说删除较旧的内核而不是较新的内核是否重要?我认为这没有任何区别。还是只是这样做,然后可以sed用来“仅打印当前内核之后的结果”?但是海事组织感到这太复杂了。为什么不像您已经做的那样简单地滤除与当前内核相对应的结果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-*东西依赖于linux-image-*东西,因此无论如何都会被删除,但是将其明确显示不会有任何伤害)。无论如何,我看不到您的分类要点。一个grep -v没有花哨的预处理的简单方法应该可以,甚至更好。我是KISS原则的支持者。这将使您以后更容易理解或调试。另外,如果不进行排序,效率会更高;)

  4. 这纯粹是出于审美目的,但是使用稍短的变体您将获得相同的输出。:-)

    $ 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


感谢您的回复@Malte,感谢您的输入。我发现您的两个第一步非常明确,它们确实使单线纸更加安全。但是,我相信您的最后两个步骤将忽略较新的内核,并对其进行清除。至少,我在我的服务器上尝试过您的解决方案,但它会卸载不需要的东西。
Alejandro 2014年

那很有意思。您能否给我两个输出,一个包含命令,其中包含我的第三和第四建议,一个不包含它们?加上的输出uname -r。对我来说,它工作正常。看看为什么它不适用于您的情况会很有趣。
Malte Skoruppa 2014年

1
我尝试向您发送邮件,但我没有找到任何电子邮件地址,因此我将在此处发布输出:hastebin.com/raleyigowe.vhdl uname -r显示我的服务器正在使用linux-image-3.8.0-34有时,服务器已下载了较新的内核,但尚未安装。这就是为什么我一直在寻找一种删除旧内核的方法。
亚历杭德罗(Alejandro)2014年

该命令为我当前的内核选择了头文件,这似乎是不可取的。
Mark Stosberg'3

1
@MalteSkoruppa,uname -r产生4.8.0-36-generic ,未能linux-headers-4.8.0-36从列表中排除。
马克·斯托斯伯格

7

我编写了此脚本,以删除版本低于当前引导版本的“ 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选项的脚本。有关脚本的更多信息,请参见此处


3

TL; DR:跳到底部。

不过要长一点。我会为您分解:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'就像马尔特建议的那样。列出相关的内核文件。
  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}'。结果是新列的版本号在原始包名称之前,如下所示:

    $ 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"-"`为我们提供以下功能:

    $ 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

再一次,“单层”的全部目的是仅删除比当前运行的内核更旧的内核(这将使所有新安装的内核仍然可用)

谢谢,让我知道它如何为您工作,以及您是否可以改善它!


检查我的答案
jarno,2015年

1

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


1
他们想要一个单线的命令。您的解决方案需要多条生产线
Anwar


0

快速解答,根据要求提供解释:

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

2
我建议(或者,如果您愿意,可以要求)扩展此范围以包括说明。:)
Eliah Kagan

@EliahKagan,我认为脚本没有意义。为什么跳过不希望安装的软件包?该脚本可能会删除比当前内核更新的内核,或者通过sed '$d'命令保存一些较旧的内核。该脚本不会删除任何linux-header软件包或与要删除的内核软件包相关的其他软件包,此外,它不会删除软件包的配置文件。我建议改用我的答案。
jarno 2015年

@EliahKagan实际上,该脚本不会删除任何软件包,但会(通过echo)打印apt-get您可以运行的命令。
jarno 2015年

0

我真的厌倦了所有这些不必要的复杂性,并创建了一个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中

希望这对其他人也有帮助。


尝试了此操作,但出现错误:“ ubuntu-old-kernel-cleanup:找不到命令”
Grant

然后它不在您的可执行搜索路径中。您是否sudo pip install ...如上所述安装了它?sudo实际上非常重要,否则pip将其安装在某些用户目录中,并且Shell可能不会在此目录中搜索可执行文件。
mrts 2016年

0
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


对我来说,这试图删除linux-libc-dev:amd64,这是不需要的。
马尔特·斯科鲁帕
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.