问题描述
我已经看到很多关于如何在 /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
。那太邪恶了! 🙂
-
列出所有
linux-*
会得到很多误报,例如(来自我的输出的示例)linux-sound-base
。即使这些可能会在稍后被您的其余命令过滤掉,但我个人觉得不首先列出它们会更安全。更好地控制要删除的软件包。不要做可能会产生意想不到的结果的事情。所以我会从\n
dpkg -l linux-{image,headers}-*\n
-
在我看来,“仅列出有数字的那些”的正则表达式有点太简单了。例如,当您在 64 位系统上时,有包
linux-libc-dev:amd64
。您的正则表达式将匹配。你不希望它匹配。诚然,如果您遵循我的第一个建议,那么linux-libc-dev:amd64
无论如何都不会被列出,但仍然如此。我们对版本号的结构比“有一个数字”这一简单事实了解得更多。此外,引用正则表达式通常是一个好主意,只是为了防止 shell 潜在的误解。所以我会做那个 egrep 命令\n
egrep '[0-9]+\\.[0-9]+\\.[0-9]+'\n
-
然后是这个排序的事情。为什么要排序?既然您无论如何都要删除所有内核(当前内核除外),那么在新内核之前删除旧内核对您来说重要吗?我不认为这有什么区别。还是您只是这样做,然后您可以使用
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 原则的支持者。它将使您以后更容易理解或调试。此外,如果没有排序,它的效率会更高;) -
这纯粹是美学,但您将使用这个稍短的变体获得相同的输出。 🙂
\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:跳到底部。
虽然它有点长。我给你分解一下:
-
dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'
就像 Malte 建议的那样。列出相关的内核文件。 -
egrep '[0-9]+\\.[0-9]+\\.[0-9]+'
Malte 还建议作为通过查找版本号仅挑选内核文件的更安全方法。 -
由于我们现在可能同时列出图像和头文件包,因此包命名可能会有所不同,因此我们有这个 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
-
现在我们必须对列表进行排序,以防止卸载任何比当前运行的图像更新的图像。
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
-
现在去掉当前和更新的内核文件
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
-
现在去掉我们用
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
-
现在我们可以将它提供给包管理器以自动删除所有内容并重新配置 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” 的重点是只删除比当前运行的内核更旧的内核(这使得任何新安装的内核仍然可用)
谢谢,让我知道这对你有什么用,如果你能改进它!