![Bash 单行命令仅删除旧内核](https://linux22.com/image/1044634/Bash%20%E5%8D%95%E8%A1%8C%E5%91%BD%E4%BB%A4%E4%BB%85%E5%88%A0%E9%99%A4%E6%97%A7%E5%86%85%E6%A0%B8.png)
我看过很多关于如何释放 /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} 结果,请确保我不会清除与当前内核相关的任何内容
- 调用 apt 来清除
这是可行的,但我确信解决方案可以更优雅并且对于生产环境来说是安全的,因为我们至少有 20 台服务器运行 Ubuntu。
感谢您的时间,亚历杭德罗。
答案1
看起来不错,只有几条注释。前两条注释使命令更安全,而第三和第四条注释使命令更短一些。您可以随意遵循或忽略其中任何一条。不过我强烈建议遵循前两条。您想确保它尽可能安全。我是认真的。您正在sudo apt-get -y purge
向一些自动生成的包列表添加一个。这太邪恶的! :)
列出所有
linux-*
将得到许多误报,例如(我的输出示例)linux-sound-base
。尽管这些可能会在稍后被你的其余命令过滤掉,但我个人认为一开始就不列出它们会更安全。最好控制要删除的软件包。不要做可能会产生意外结果的事情。所以我会从dpkg -l linux-{image,headers}-*
我认为,您“仅列出带有数字的版本”的正则表达式有点过于简单。例如,
linux-libc-dev:amd64
当您在 64 位系统上时,会出现软件包。您的正则表达式将匹配。您不希望它匹配。诚然,如果您遵循了我的第一个建议,那么linux-libc-dev:amd64
无论如何都不会被列出,但仍然如此。我们对版本号的结构的了解多于简单的“有一个数字”这一事实。此外,引用正则表达式通常是一个好主意,只是为了防止 shell 可能误解。所以我会制作那个 egrep 命令egrep '[0-9]+\.[0-9]+\.[0-9]+'
然后就是排序的事情。为什么要排序?既然你无论如何都要删除所有内核(当前内核除外),那么在删除较旧的内核之前删除较新的内核是否重要?我认为这没什么区别。或者你这样做只是为了可以使用
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
删除 sorting/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 原则的支持者。它将使您以后更容易理解或调试。此外,没有排序会稍微更有效率 ;)这纯粹是出于美观考虑,但使用这个稍短的变体您将获得相同的输出。:-)
$ 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
。
答案2
我编写了这个脚本,用于删除版本低于当前启动版本的“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:跳至底部。
不过,它确实有点长。我来给你分解一下:
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}'
结果是在原始包名称之前有一个新的列,其中包含版本号,如下所示:$ 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
现在我们必须对列表进行排序,以防止卸载任何比当前正在运行的图像更新的图像。
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
现在删除当前和较新的内核文件,
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
现在去掉我们添加的第一列
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
现在我们可以将其提供给包管理器以自动删除所有内容并重新配置 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
再次强调,这句“一行”命令的重点是只删除比当前正在运行的内核更旧的内核(这使得任何新安装的内核仍然可用)
谢谢,让我知道这对您有何作用以及您是否可以改进它!
答案4
您可以使用“ls”命令简单地列出 /boot 目录以查看您拥有的内核版本。然后使用“sudo apt-get -y purge "xxx"”,其中“xxx”替换为您要删除的版本号。注意它不是您当前正在运行的版本!!