Cómo purgar selectivamente los kernels viejos de una sola vez

7

La alta calificación de Q & amp; A ¿Cómo elimino las versiones viejas del kernel para limpiar el menú de arranque? no proporciona una manera fácil de purgar selectivamente núcleos más antiguos a menos que se instalen aplicaciones adicionales, por ejemplo, Ubuntu-Tweak .

El Bash one-liner para eliminar solo kernels viejos Q & amp; A da una solución de "purga todo lo viejo", pero quiero mantener el último kernel en cada generación. es decir, eliminar 4.7.1, 4.7.2 ... pero mantener 4.7.5.

¿Hay alguna manera de desplazarse por una lista de todos los núcleos instalados y seleccionar los específicos para purgar? No debería permitir el purgado del núcleo actualmente en ejecución.

    
pregunta WinEunuuchs2Unix 11.03.2017 - 20:05

1 respuesta

5

La ventaja de esta respuesta es nativa. Ubuntu Bash se usa sin instalar aplicaciones de terceros. Los usuarios de kernels personalizados que no usaron apt o dpkg pueden cambiar este script bash para satisfacer sus necesidades.

Solución basada en Zenity

Zenity proporciona una interfaz GUI para la terminal. Aquí se usa para procesar una lista de kernels y seleccionar los individuales:

El título del cuadro de diálogo informa la cantidad de kernels, su tamaño total y la versión actual del núcleo arrancada. El kernel actual se excluye de los totales del título y no aparece en la lista del kernel.

La Fecha de modificación es normalmente la fecha en que se lanzó el kernel. En mi sistema, esa fecha "se toca" cada vez que se inicia el kernel usando un script de reinicio cron ( ¿Cómo puede saber cuándo se inició por última vez una versión de kernel específica? ).

Para cada núcleo se informa su tamaño dentro del directorio /boot . Luego, el tamaño total del kernel se suma para los tres directorios; / boot, / usr / src / kernel_version y / lib / modules / kernel_version .

Si no se pasa ningún parámetro a rm-kernels , se estima el tamaño total y el título muestra "Est. Total". Esto ahorra tiempo ejecutando el comando du que puede tomar de 30 segundos a 90 minutos, dependiendo de cuántos kernels tiene y si tiene una SSD o una HDD. Si pasa cualquier parámetro, entonces du se usa para obtener tamaños de kernel y el título muestra "Total real" como lo muestra la pantalla de muestra anterior.

apt-get purge te da la oportunidad de abortar

Puede ver todo lo que será purgado por apt purge y se le da la opción de continuar o cancelar:

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 informa que se liberarán 1.784 MB, pero el total real será de 2.379 MB. No sé por qué es diferente.

En lugar de purgar kernels uno a la vez y update-grub repetitivamente en un ciclo que consume mucho tiempo, las selecciones se depuran todas a la vez.

El código

Copia este código a un archivo llamado rm-kernels en /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

NOTA: necesitas utilizar sudo poderes para guardar el archivo con tu editor favorito.

Para hacer que el archivo ejecutable use:

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

Versión del servidor

rm-kernels-server es la versión del servidor para eliminar kernels selectivamente de una vez. En lugar de un cuadro de diálogo GUI (gráfico), se usa un cuadro de diálogo basado en texto para seleccionar kernels para purgar.

  • Antes de ejecutar el script, debe instalar la función de diálogo usando:

    sudo apt install dialog

Dialog está en la instalación predeterminada de Ubuntu Desktop pero no en Ubuntu Server.

Pantalla de muestra

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

NOTA: en la llamada a dialog , la directiva --ascii-lines se pasa para reemplazar el juego de caracteres extendidos de trazado de línea (que a ssh no le gusta) con "+ --- - + "para cuadros de dibujo. Si no le gusta esta apariencia, puede usar la directiva --no-lines para ninguna casilla. Si no usa ssh , puede eliminar --ascii-lines y su pantalla se formateará con caracteres de trazado de línea:

Actualizaciones del 28 de julio de 2017

El tamaño calculado de cada núcleo se tomó de /boot/*kernel_version* , que eran 5 archivos que suman ~ 50 MB. La fórmula ha cambiado para incluir los archivos en /usr/src/*kernel_version* y /lib/modules/*kernel_version* . El tamaño calculado para cada núcleo ahora es ~ 400 MB.

El valor predeterminado es estimar el tamaño de los archivos para linux-headers en 125 MB y linux-image en 220 MB porque du puede ser muy lento a menos que los archivos estén en caché en la memoria. Para obtener el tamaño real usando du pase cualquier parámetro al script.

El total de todos los tamaños de kernel (excluyendo la versión en ejecución actual que no se puede eliminar) se muestra ahora en la barra de título.

El cuadro de diálogo utilizado para mostrar la última fecha de acceso del núcleo . Esta fecha puede sobrescribirse en masa para todos los núcleos durante la copia de seguridad u operaciones similares. El cuadro de diálogo ahora muestra la Fecha modificada en su lugar.

Actualizaciones del 5 de agosto de 2017

La lista del núcleo ahora está ordenada por Kernel Version en lugar de alfa-numéricamente.

Se agregó una columna adicional para /boot size . En la versión gráfica de Zenity, la última columna cambia entre "Total real" y "Total estimado" (Estimado) según el parámetro 1 que se apruebe o no.

    
respondido por el WinEunuuchs2Unix 11.03.2017 - 20:05

Lea otras preguntas en las etiquetas