Como remover seletivamente kernels antigos de uma só vez

7

O altamente cotado Q & amp; A Como eu removo versões antigas do kernel para limpar o menu de inicialização? não oferece uma maneira fácil de remover seletivamente kernels antigos, a menos que aplicativos extras estejam instalados, por exemplo, Ubuntu-Tweak .

O Bash one-liner para excluir apenas kernels antigos Q & amp; A fornece uma solução "purge everything old", mas quero manter o último kernel em cada geração. ou seja, remova 4.7.1, 4.7.2 ... mas mantenha 4.7.5.

Existe uma maneira de percorrer uma lista de todos os kernels instalados e selecionar os específicos a serem eliminados? Ele não deve permitir a limpeza do kernel em execução no momento.

    
por WinEunuuchs2Unix 11.03.2017 / 20:05

1 resposta

5

A vantagem desta resposta é nativa O Ubuntu Bash é usado sem instalar aplicativos de terceiros. Os usuários de kernels personalizados que não usaram apt ou dpkg podem alterar este script bash para atender às suas necessidades.

Solução baseada no Zenity

O Zenity fornece uma interface GUI para o terminal. Aqui é usado para processar uma lista de kernels e selecionar os individuais:

O título da caixa de diálogo informa o número de kernels, seu tamanho total e a versão atual do kernel inicializada. O kernel atual é excluído dos totais do título e não aparece na lista do kernel.

A data de modificação é normalmente a data em que o kernel foi lançado. No meu sistema essa data é "tocada" toda vez que o kernel é inicializado usando um script de reinicialização cron (du , o que pode levar de 30 segundos a 90 minutos, dependendo de quantos kernels você tem e se você tem um SSD ou um HDD. Se você passar qualquer parâmetro, então du é usado para obter tamanhos de kernel e o título mostra "Real Total", como mostra a tela de amostra acima.

apt-get purge dá chance de abortar

Você pode ver tudo o que será removido por apt purge e terá a opção de prosseguir ou abortar:

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 relatórios 1.784 MB serão liberados, mas o total real é de 2.379 MB. Eu não sei porque é diferente.

Em vez de limpar os kernels um de cada vez e update-grub ser repetidamente chamado em loop demorado, as seleções são limpas de uma vez.

O código

Copie este código para um arquivo chamado rm-kernels in /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

OBSERVAÇÃO: você precisa usar sudo powers para salvar o arquivo com seu editor favorito.

Para tornar o uso de arquivos executável:

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

Versão do servidor

rm-kernels-server é a versão do servidor para excluir seletivamente os kernels de uma só vez. Em vez de uma caixa de diálogo GUI (gráfica), uma caixa de diálogo baseada em texto é usada para selecionar os kernels a serem eliminados.

  • Antes de executar o script, você precisa instalar a função de diálogo usando:

    sudo apt install dialog

O Dialog está na instalação padrão do Ubuntu Desktop, mas não no Ubuntu Server.

Ecrã de amostra

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

OBSERVAÇÃO: Na chamada para dialog , a diretiva --ascii-lines é passada para substituir o conjunto de caracteres estendidos de extração de linha (que ssh não gosta) com "+ --- - + "para caixas de desenho. Se você não gostar dessa aparência, poderá usar a diretiva --no-lines para nenhuma caixa. Se você não estiver usando ssh , poderá excluir o --ascii-lines e sua exibição será formatada com caracteres de desenho de linha:

Atualizações de 28 de julho de 2017

O tamanho calculado de cada kernel foi retirado de /boot/*kernel_version* , que eram 5 arquivos, totalizando ~ 50 MB. A fórmula foi alterada para incluir os arquivos em /usr/src/*kernel_version* e /lib/modules/*kernel_version* . O tamanho calculado para cada kernel é agora ~ 400 MB.

O padrão é estimar o tamanho dos arquivos para os cabeçalhos linux em 125 MB e a imagem linux para 220 MB, porque du pode ser dolorosamente lento, a menos que os arquivos estejam em cache na memória. Para obter o tamanho real usando du , passe qualquer parâmetro para o script.

O total de todos os tamanhos de kernel (excluindo a versão atual em execução que não pode ser removida) agora é mostrado na barra de título.

A caixa de diálogo usada para exibir a <Última> Data de Último Acesso de cada Kernel. Essa data pode ser sobregravada em massa para todos os kernels durante operações de backup ou semelhantes. A caixa de diálogo agora mostra a Data Modificada em seu lugar.

Atualizações de 5 de agosto de 2017

A lista do kernel agora é classificada por Versão do Kernel, em vez de alfa-numericamente.

Uma coluna adicional foi adicionada para /boot size . Na versão gráfica do Zenity, a última coluna muda entre "Real Total" e "Est. Total" (Estimado) dependendo do parâmetro 1 sendo passado ou não.

    
por WinEunuuchs2Unix 11.03.2017 / 20:05