Как выборочно очистить все старые ядра сразу
Q&A с высоким рейтингом Как удалить старые версии ядра, чтобы очистить меню загрузки? не предоставляет простой способ выборочной очистки старых ядер, если не установлены дополнительные приложения, например Ubuntu-Tweak.
Однострочное использование Bash для удаления только старых ядер Q&A дает решение "очистить все старое", но я хочу сохранить последнее ядро в каждом поколении. то есть удалить 4.7.1, 4.7.2... но сохранить 4.7.5.
Есть ли способ прокрутить список всех установленных ядер и выбрать конкретные для очистки? Он не должен разрешать очистку работающего в данный момент ядра.
1 ответ
Преимущество этого ответа в том, что нативный Ubuntu Bash используется без установки сторонних приложений. Пользователи кастомных ядер, которые не использовали apt
или же dpkg
можете изменить этот сценарий bash в соответствии с их потребностями.
Решение на основе Zenity
Zenity предоставляет графический интерфейс для терминала. Здесь он используется для обработки списка ядер и выбора отдельных:
В заголовке диалога указывается количество ядер, их общий размер и текущая версия ядра. Текущее ядро исключено из итогов заголовка и не отображается в списке ядра.
Дата изменения - это обычно дата выпуска ядра. В моей системе эта дата "затрагивается" каждый раз, когда ядро загружается с помощью сценария перезагрузки cron ( Как узнать, когда конкретная версия ядра загружалась в последний раз?).
Для каждого ядра его размер в пределах /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
сообщает, что будет освобождено 1784 МБ, а реальное - 2 379 МБ. Я не знаю, почему это отличается.
Вместо того, чтобы очищать ядра по одному и update-grub
будучи повторно вызванным в длительном цикле, выборки очищаются все сразу.
Код
Скопируйте этот код в файл с именем rm-kernels
в /usr/local/bin
:
#!/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 )); i<end; i++ )); do
SortedArr+=("${choices[i]}")
done
done < ~/.rm-kernels-ndx
rm ~/.rm-kernels-plain ~/.rm-kernels-sorted ~/.rm-kernels-ndx
if [[ $# -ne 0 ]] ; then # Was a parameter passed?
VariableHeading="Real Total"
else
VariableHeading="Est. Total"
fi
# adjust width & height below for your screen 640x480 default for 1920x1080 HD screen
# also adjust font="14" below if blue text is too small or too large
choices=(`zenity \
--title "rm-kernels - $n Kernels, Total: $t MB excluding: $current_version" \
--list \
--separator="$IFS" \
--checklist --multiple \
--text '<span foreground="blue" font="14">Check box next to kernel(s) to remove</span>' \
--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 w.x.y-zzz headers
list="$list""linux-image-$choice- linux-headers-$short_choice"
else
# Remove w.x.y-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
версия сервера для выборочного удаления всех ядер одновременно Вместо графического диалогового окна с графическим интерфейсом используется текстовое диалоговое окно для выбора очищаемых ядер.
Перед запуском скрипта необходимо установить функцию диалога, используя:
sudo apt install dialog
Диалог находится в стандартной установке Ubuntu Desktop, но не в Ubuntu Server.
Образец экрана
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 w.x.y-zzz headers
list="$list""linux-image-$choice- linux-headers-$short_choice"
else
# Remove w.x.y-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
и ваш дисплей будет отформатирован с помощью символов рисования линий:
28 июля 2017 г. Обновления
Расчетный размер каждого ядра был взят из /boot/*kernel_version*
которые были 5 файлов на общую сумму ~50 МБ. Формула была изменена, чтобы включить файлы в /usr/src/*kernel_version*
а также /lib/modules/*kernel_version*
, Расчетный размер для каждого ядра теперь составляет ~400 МБ.
По умолчанию размер файлов для linux-заголовков оценивается в 125 МБ, а для linux-образа - в 220 МБ, потому что du
может быть мучительно медленным, если файлы не кэшируются в памяти. Чтобы получить реальный размер, используя du
передать любой параметр в скрипт.
Сумма всех размеров ядра (за исключением текущей работающей версии, которую нельзя удалить) теперь отображается в строке заголовка.
Диалоговое окно, используемое для отображения даты последнего доступа каждого ядра. Эта дата может быть перезаписана для всех ядер во время резервного копирования или аналогичных операций. Теперь в диалоговом окне отображается Дата изменения.
5 августа 2017 г. Обновления
Список ядра теперь отсортирован по версии ядра, а не по алфавиту.
Добавлен дополнительный столбец для /boot size
, В графической версии Zenity последний столбец изменяется между "Реальным итогом" и "Итоговым итогом" (оценочным) в зависимости от того, передан параметр 1 или нет.