Как выборочно очищать старые ядра одновременно

7

Высокий рейтинг Q & amp; A Как удалить старые версии ядра для очистки меню загрузки? не предоставляет простой способ выборочной очистки старых ядер, если не установлены дополнительные приложения, т.е. Ubuntu-Tweak .

Bash one-liner для удаления только старых ядер Q & amp; A дает "очистить все старое" решение, но я хочу сохранить последнее ядро ​​в каждом поколении. т.е. удалить 4.7.1, 4.7.2 ... но сохранить 4.7.5.

Есть ли способ прокрутить список всех установленных ядер и выбрать конкретные для очистки? Он не должен позволять очищать текущее ядро.

    
задан WinEunuuchs2Unix 11.03.2017 в 19:05
источник

1 ответ

5

Преимущество этого ответа - родной Ubuntu Bash используется без установки сторонних приложений. Пользователи пользовательских ядер, которые не использовали apt или dpkg , могут изменить этот сценарий bash в соответствии с их потребностями.

Решение на основе Zenity

Zenity предоставляет интерфейс GUI для терминала. Здесь он используется для обработки списка ядер и выбора отдельных:

В заголовке диалога сообщается количество ядер, их общий размер и текущая версия ядра. Текущее ядро ​​исключено из итогов заголовка и не отображается список ядра.

Дата изменения обычно является датой выпуска ядра. В моей системе эта дата "тронула" каждый раз, когда ядро ​​загружается с помощью сценария перезагрузки cron ( Как узнать, когда была загружена последняя версия ядра? ).

Для каждого ядра сообщается о его размере в каталоге /boot . Затем общий размер ядра суммируется для трех каталогов; / boot, / usr / src / kernel_version и / lib / modules / kernel_version .

Если ни один параметр не передан в rm-kernels , общий размер оценивается, а в заголовке отображается "Est. Total". Это экономит время, затрачивая команду du , которая может занять от 30 секунд до 90 минут в зависимости от того, сколько ядер у вас есть, и есть ли у вас SSD или жесткий диск. Если вы передаете какой-либо параметр вообще, то 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 МБ будет освобожден, но реальная общая сумма составляет 2379 МБ. Я не знаю, почему это другое.

Вместо того, чтобы продувать ядра по одному, а 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 }')

    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 }')
        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 }')
    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 - это версия сервера для выборочного удаления ядер одновременно. Вместо диалогового окна GUI (графического) текстовое диалоговое окно используется для выбора ядер для очистки.

  • Перед запуском скрипта вам необходимо установить функцию диалога , используя:

    sudo apt install dialog

Диалог находится в установленной по умолчанию установке Ubuntu Desktop, но не на сервере Ubuntu.

Пример экрана

rm-kernels-server bash code

#!/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 }')

    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 }')
        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 }')
    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 последний столбец изменяется между "Реальным итогом" и "Est. Total" (Оценочный) в зависимости от передаваемого параметра 1.

    
ответ дан WinEunuuchs2Unix 11.03.2017 в 19:05
источник