如何有选择地一次性清除旧内核

高度评价的Q&A 如何删除旧内核版本以清理启动菜单? 除非安装了额外的应用程序,即Ubuntu-Tweak,否则不提供有选择地清除旧内核的简单方法。

Bash one-liner只删除旧内核 Q&A给出了“清除一切旧”的解决方案,但我想保留每一代的最后一个内核。 即删除4.7.1,4.7.2 ……但保留4.7.5。

有没有办法滚动浏览所有已安装内核的列表并选择要清除的特定内核? 它不应该允许清除当前运行的内核。

这个答案的优点是使用本机Ubuntu Bash而无需安装第三方应用程序。 不使用aptdpkg的自定义内核用户可以更改此bash脚本以满足他们的需要。

基于Zenity的解决方案

Zenity为终端提供GUI界面。 在这里,它用于处理内核列表并选择单个内核:

rm-kernels 1.png

对话框标题报告内核的数量,它们的总大小和引导的当前内核版本。 当前内核从标题的总数中排除,并且不会出现在内核列表中。

修改日期通常是内核发布的日期。 在我的系统上,每次使用cron reboot脚本启动内核时都会“触摸”日期( 如何找到上次启动特定内核版本的时间? )。

对于每个内核,报告其在/boot目录中的大小。 然后将内核的总大小相加为三个目录; / boot,/ usr / src / kernel_version和/ lib / modules / kernel_version

如果没有参数传递给rm-kernels ,则估计总大小,标题显示“Est.Total”。 这样可以节省运行du命令的时间,这可能需要30秒到90分钟,具体取决于您拥有的内核数量以及是否有SSD或HDD。 如果您完全传递任何参数,则du用于获取内核大小,标题显示“Real Total”,如上面的示例屏幕所示。

apt-get purge让你有机会中止

您可以查看将通过apt purge所有内容,并可以选择继续或中止:

 The following packages will be REMOVED: linux-headers-4.4.0-78* linux-headers-4.4.0-78-generic* linux-headers-4.4.8-040408* linux-headers-4.4.8-040408-generic* linux-headers-4.6.3-040603* linux-headers-4.6.3-040603-generic* linux-headers-4.8.12-040812* linux-headers-4.8.12-040812-generic* linux-headers-4.9.0-040900* linux-headers-4.9.0-040900-generic* linux-headers-4.9.9-040909* linux-headers-4.9.9-040909-generic* linux-image-4.4.0-78-generic* linux-image-4.4.8-040408-generic* linux-image-4.6.3-040603-generic* linux-image-4.8.12-040812-generic* linux-image-4.9.0-040900-generic* linux-image-4.9.9-040909-generic* linux-image-extra-4.4.0-78-generic* 0 upgraded, 0 newly installed, 19 to remove and 1 not upgraded. After this operation, 1,794 MB disk space will be freed. Do you want to continue? [Y/n] 

apt purge报告将释放1,784 MB,但实际总数为2,379 MB。 我不知道为什么会有所不同。

不是一次清除一个内核而是在耗时的循环中重复调用update-grub而是一次性清除所有选择。

代码

将此代码复制到/usr/local/bin名为rm-kernels的文件中:

 #!/bin/bash # NAME: rm-kernels # PATH: /usr/local/bin # DESC: Provide zenity item list of kernels to remove # DATE: Mar 10, 2017. Modified Aug 5, 2017. # NOTE: Will not delete current kernel. # With 10 kernels on an SSD, empty cache from sudo prompt (#) using: # # free && sync && echo 3 > /proc/sys/vm/drop_caches && free # First time for `du` 34 seconds. # Second time for `du` 1 second. # With a magnetic hard disk, and empty memory cache: # the first `du` command averages about 20 seconds per kernel. # the second `du` command averages about 2.5 seconds per kernel. # PARM: If any parm 1 passed use REAL kernel size, else use estimated size. # By default `du` is not used and estimated size is displayed. # Must be running as sudo if [[ $(id -u) != 0 ]]; then zenity --error --text "root access required. Use: sudo rm-kernels" exit 99 fi OLDIFS="$IFS" IFS="|" choices=() current_version=$(uname -r) for f in /boot/vmlinuz* do if [[ $f == *"$current_version"* ]]; then continue; fi # skip current version [[ $f =~ vmlinuz-(.*) ]] v=${BASH_REMATCH[1]} # example: 4.9.21-040921-generic v_main="${v%-*}" # example: 4.9.21-040921 n=$(( n + 1 )) # increment number of kernels # Kernel size in /boot/*4.9.21-040921-generic* s=$(du -ch /boot/*-$v* | awk '/total/{print $1}') if [[ $# -ne 0 ]] ; then # Was a parameter passed? if [[ -d "/usr/src/linux-headers-"$v_main ]] ; then # Kernel headers size in /usr/src/*4.9.21-040921* s2=$(du -ch --max-depth=1 /usr/src/*-$v_main* | awk '/total/{print $1}') else s2="0M" # Linux Headers are not installed fi # Kernel image size in /lib/modules/4.9.21-040921-generic* s3=$(du -ch --max-depth=1 /lib/modules/$v* | awk '/total/{print $1}') else # Estimate sizof of optional headers at 125MB and size of image at 220MB if [[ -d "/usr/src/linux-headers-"$v_main ]] ; then s2="125M" else s2="0M" # Linux Headers are not installed fi s3="220M" fi # Strip out "M" provided by human readable option of du and add 3 sizes together c=$(( ${s//[^0-9]*} + ${s2//[^0-9]*} + ${s3//[^0-9]*} )) s=$(( ${s//[^0-9]*} )) # Strip out M to make " MB" below which looks nicer t=$(( t + c )) s=$s" MB" c=$c" MB" d=$(date --date $(stat -c %y $f) '+%b %d %Y') # Last modified date for display choices=("${choices[@]}" false "$v" "$d" "$s" "$c") done # Write Kernel version and array index to unsorted file > ~/.rm-kernels-plain # Empty any existing file. for (( i=1; i<${#choices[@]}; i=i+5 )) ; do echo "${choices[i]}|$i" >> ~/.rm-kernels-plain done # Sort kernels by version number sort -V -k1 -t'|' ~/.rm-kernels-plain -o ~/.rm-kernels-sorted # Strip out keys leaving Sorted Index Numbers cut -f2 -d '|' ~/.rm-kernels-sorted > ~/.rm-kernels-ndx # Create sorted array SortedArr=() while read -r ndx; do end=$(( ndx + 4 )) for (( i=$(( ndx - 1 )); iCheck box next to kernel(s) to remove' \ --width=800 \ --height=480 \ --column "Select" \ --column "Kernel Version Number" \ --column "Modified Date" \ --column "/boot Size" \ --column "$VariableHeading" \ "${SortedArr[@]}"`) IFS="$OLDIFS" i=0 list="" for choice in "${choices[@]}" ; do if [ "$i" -gt 0 ]; then list="$list- "; fi # append "-" from last loop ((i++)) short_choice=$(echo $choice | cut -f1-2 -d"-") header_count=$(find /usr/src/linux-headers-$short_choice* -maxdepth 0 -type d | wc -l) # If -lowlatency and -generic are purged at same time the _all header directory # remains on disk for specific version with no -generic or -lowlatency below. if [[ $header_count -lt 3 ]]; then # Remove all wxy-zzz headers list="$list""linux-image-$choice- linux-headers-$short_choice" else # Remove wxy-zzz-flavour header only, ie -generic or -lowlatency list="$list""linux-image-$choice- linux-headers-$choice" fi done if [ "$i" -gt 0 ] ; then apt-get purge $list fi 

注意:您需要使用sudo权限来使用您喜欢的编辑器保存文件。

要使文件可执行使用:

 sudo chmod +x /usr/local/bin/rm-kernels 

服务器版本

rm-kernels-server是有选择地一次性删除内核的服务器版本。 而不是GUI(图形)对话框,使用基于文本的对话框来选择要清除的内核。

  • 在运行脚本之前,您需要使用以下命令安装对话框function

    sudo apt install dialog

Dialog是默认的Ubuntu Desktop安装,但不在Ubuntu Server中。

样本屏幕

rm-kernels-server 1

rm-kernels-server bash代码

 #!/bin/bash # NAME: rm-kernels-server # PATH: /usr/local/bin # DESC: Provide dialog checklist of kernels to remove # Non-GUI, text based interface for server distro's. # DATE: Mar 10, 2017. Modified Aug 5, 2017. # NOTE: Will not delete current kernel. # With 10 kernels on an SSD, empty cache from sudo prompt (#) using: # # free && sync && echo 3 > /proc/sys/vm/drop_caches && free # First time for `du` 34 seconds. # Second time for `du` 1 second. # With a magnetic hard disk, and empty memory cache: # the first `du` command averages about 20 seconds per kernel. # the second `du` command averages about 2.5 seconds per kernel. # PARM: If any parm 1 passed use REAL kernel size, else use estimated size. # By default `du` is not used and estimated size is displayed. # Must be running as sudo if [[ $(id -u) != 0 ]]; then echo "root access required. Use: sudo rm-kernels-server" exit 99 fi # Must have the dialog package. On Servers, not installed by default command -v dialog >/dev/null 2>&1 || { echo >&2 "dialog package required but it is not installed. Aborting."; exit 99; } OLDIFS="$IFS" IFS="|" item_list=() # Deviate from rm-kernels here. current_version=$(uname -r) i=0 for f in /boot/vmlinuz* do if [[ $f == *"$current_version"* ]]; then continue; fi # skip current version [[ $f =~ vmlinuz-(.*) ]] ((i++)) # Item List v=${BASH_REMATCH[1]} # example: 4.9.21-040921-generic v_main="${v%-*}" # example: 4.9.21-040921 n=$(( n + 1 )) # increment number of kernels # Kernel size in /boot/*4.9.21-040921-generic* s=$(du -ch /boot/*-$v* | awk '/total/{print $1}') if [[ $# -ne 0 ]] ; then # Was a parameter passed? if [[ -d "/usr/src/linux-headers-"$v_main ]] ; then # Kernel headers size in /usr/src/*4.9.21-040921* s2=$(du -ch --max-depth=1 /usr/src/*-$v_main* | awk '/total/{print $1}') else s2="0M" # Linux Headers are not installed fi # Kernel image size in /lib/modules/4.9.21-040921-generic* s3=$(du -ch --max-depth=1 /lib/modules/$v* | awk '/total/{print $1}') else # Estimate sizof of optional headers at 125MB and size of image at 220MB if [[ -d "/usr/src/linux-headers-"$v_main ]] ; then s2="125M" else s2="0M" # Linux Headers are not installed fi s3="220M" fi # Strip out "M" provided by human readable option of du and add 3 sizes together c=$(( ${s//[^0-9]*} + ${s2//[^0-9]*} + ${s3//[^0-9]*} )) s=$(( ${s//[^0-9]*} )) # Strip out M to make " MB" below which looks nicer t=$(( t + c )) s=$s" MB" c=$c" MB" d=$(date --date $(stat -c %y $f) '+%b %d %Y') # Last modified date for display item_list=("${item_list[@]}" "$i" "$v ! $d ! $s ! $c" off) done # Write Kernel version and array index to unsorted file > ~/.rm-kernels-plain # Empty any existing file. for (( i=1; i<${#item_list[@]}; i=i+3 )) ; do echo "${item_list[i]}|$i" >> ~/.rm-kernels-plain done # Sort kernels by version number sort -V -k1 -t'|' ~/.rm-kernels-plain -o ~/.rm-kernels-sorted # Strip out keys leaving Sorted Index Numbers cut -f2 -d '|' ~/.rm-kernels-sorted > ~/.rm-kernels-ndx # Create sorted array SortedArr=() i=1 while read -r ndx; do SortedArr+=($i "${item_list[$ndx]}" "off") (( i++ )) done < ~/.rm-kernels-ndx rm ~/.rm-kernels-plain ~/.rm-kernels-sorted ~/.rm-kernels-ndx cmd=(dialog --backtitle "rm-kernels-server - $n Kernels, Total: $t MB excluding: $current_version" \ --title "Use space bar to toggle kernel(s) to remove" \ --column-separator "!" \ --separate-output \ --ascii-lines \ --checklist " Kernel Version ------ Modified Date /boot Size Total" 20 70 15) selections=$("${cmd[@]}" "${SortedArr[@]}" 2>&1 >/dev/tty) IFS=$OLDIFS if [ $? -ne 0 ] ; then echo cancel selected exit 1 fi i=0 choices=() for select in $selections ; do ((i++)) j=$(( 1 + ($select - 1) * 3 )) choices[i]=$(echo ${SortedArr[j]} | cut -f1 -d"!") done i=0 list="" for choice in "${choices[@]}" ; do if [ "$i" -gt 0 ]; then list="$list- "; fi # append "-" from last loop ((i++)) short_choice=$(echo $choice | cut -f1-2 -d"-") header_count=$(find /usr/src/linux-headers-$short_choice* -maxdepth 0 -type d | wc -l) # If -lowlatency and -generic are purged at same time the _all header directory # remains on disk for specific version with no -generic or -lowlatency below. if [[ $header_count -lt 3 ]]; then # Remove all wxy-zzz headers list="$list""linux-image-$choice- linux-headers-$short_choice" else # Remove wxy-zzz-flavour header only, ie -generic or -lowlatency list="$list""linux-image-$choice- linux-headers-$choice" fi done if [ "$i" -gt 0 ] ; then apt-get purge $list fi 

注意:在调用dialog ,指令--ascii-lines被传递给替换线条绘制扩展字符集( ssh不喜欢)和“+ —– +”用于绘图框。 如果您不喜欢这种外观,则可以使用--no-lines指令完全没有框。 如果你没有使用ssh你可以删除--ascii-lines ,你的显示将用线条绘制字符格式化:

rm-kernels-server line draw


2017年7月28日更新

每个内核的计算大小取自/boot/*kernel_version* ,这是5个文件,总计约50 MB。 公式已更改为包含/usr/src/*kernel_version*/lib/modules/*kernel_version* 。 每个内核的计算大小现在约为400 MB。

默认情况下,估计linux-headers的文件大小为125 MB,linux-image为220 MB,因为除非文件缓存在内存中,否则du会非常缓慢。 要使用du获取实际大小,请将任何参数传递给脚本。

现在,标题栏中显示了所有内核大小(不包括当前正在运行的版本,无法删除)的总和。

用于显示每个内核的上次访问日期的对话框。 在备份或类似操作期间,可以为所有内核大量覆盖此日期。 该对话框现在显示修改日期


2017年8月5日更新

内核列表现在按内核版本排序,而不是按字母数字排序。

/boot size添加了一个附加列。 在图形Zenity版本中,最后一列在“Real Total”和“Est.Total”(Estimated)之间变化,具体取决于传递的参数1。