web-dev-qa-db-fra.com

Bash one-liner pour ne supprimer que les anciens noyaux

J'ai vu beaucoup de discussions sur la façon de libérer de l'espace sur la partition/boot et c'est également mon objectif. Cependant, je ne suis intéressé que par la suppression des noyaux anciens et non chacun d'eux, mais du noyau actuel.

J'ai besoin de la solution pour être un one-liner puisque je vais exécuter le script de Puppet et je ne veux pas avoir de fichiers supplémentaires à traîner. Jusqu'à présent, j'ai obtenu ce qui suit:

dpkg -l linux-* | awk '/^ii/{print $2}' | egrep [0-9] | sort -t- -k3,4 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | xargs Sudo apt-get -y purge

Pour être plus précis, ce qu'il fait pour le moment est le suivant:

  • Lister tous les paquets linux- * et imprimer leurs noms.
  • Ne listez que ceux qui ont des nombres et triez-les, en retournant le résultat inverse. De cette façon, les noyaux les plus anciens sont listés en dernier.
  • N'affiche que les résultats qui suivent le noyau actuel
  • Puisqu'il y a des résultats linux- {image, en-têtes}, assurez-vous que je ne purgerai rien de ce qui est lié à mon noyau actuel.
  • Appeler apte à purger

Cela fonctionne, mais je suis sûr que la solution peut être plus élégante et qu'elle est sans danger pour un environnement de production, car au moins 20 de nos serveurs utilisent Ubuntu.

Merci pour votre temps, Alejandro.

22
Alejandro

A l'air assez sympa, juste quelques commentaires. Les deux premiers commentaires rendent la commande plus sûre, tandis que les troisième et quatrième la raccourcissent un peu. N'hésitez pas à les suivre ou à les ignorer. Bien que je conseille fortement de suivre les deux premiers. Vous voulez vous assurer que c'est aussi sûr que possible. Je veux dire sérieusement. Vous lancez un Sudo apt-get -y purge sur une liste de paquets générée automatiquement. C'est tellement mal! :)

  1. En répertoriant tous les linux-*, vous obtiendrez de nombreux faux positifs, tels que (exemple tiré de ma sortie) linux-sound-base. Bien que ceux-ci puissent être filtrés plus tard par le reste de votre commande, je me sentirais personnellement plus en sécurité de ne pas les énumérer en premier lieu. Mieux contrôler les paquets que vous souhaitez supprimer. Ne faites pas des choses qui peuvent avoir des résultats inattendus. Donc je commencerais par

    dpkg -l linux-{image,headers}-*
    
  2. Votre regex de "ne lister que ceux qui ont des chiffres" est un peu trop simple à mon avis. Par exemple, il existe le package linux-libc-dev:AMD64 lorsque vous utilisez un système 64 bits. Votre regex correspondra. Vous ne voulez pas que cela corresponde. Certes, si vous avez suivi mon premier conseil, alors linux-libc-dev:AMD64 ne sera pas listé de toute façon, mais quand même. Nous en savons plus sur la structure d'un numéro de version que le simple fait "il y a un numéro". De plus, c’est généralement une bonne idée de citer des expressions rationnelles afin d’éviter toute interprétation erronée de la part de Shell. Donc, je voudrais faire cette commande egrep

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
    
  3. Ensuite, il y a cette chose de tri. Pourquoi vous triez? Puisque de toute façon vous allez supprimer tous les noyaux (à l'exception du noyau actuel), est-il important que vous supprimiez les plus anciens avant les plus récents? Je ne pense pas que cela fasse une différence. Ou faites-vous seulement cela pour que vous puissiez ensuite utiliser sed pour "Imprimer uniquement les résultats qui suivent le noyau actuel"? Mais, à l’OMI, cela semble beaucoup trop compliqué. Pourquoi ne pas simplement filtrer les résultats correspondant à votre noyau actuel, comme vous le faites déjà avec grep -v de toute façon, et le faire? Honnêtement, si je prends la première partie de votre commande (avec mes deux suggestions précédentes intégrées), je reçois sur ma machine

    $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | sort -t- -k3,4 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`
    linux-image-3.8.0-34-generic
    linux-image-3.5.0-44-generic
    

    Enlever ce genre de tris/sed, je reçois

    $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | grep -v -e `uname -r | cut -f1,2 -d"-"`
    linux-image-3.5.0-44-generic
    linux-image-3.8.0-34-generic
    linux-image-extra-3.5.0-44-generic
    linux-image-extra-3.8.0-34-generic
    

    Donc, votre commande plus compliquée raterait en fait deux paquets sur ma machine, que je voudrais supprimer (maintenant, il est possible que ces linux-image-extra-* thingys dépendent du linux-image-* thingys et soient donc supprimés de toute façon, mais il n’est pas inutile de les expliciter. ). En tout cas, je ne vois pas l'intérêt de votre tri; Un simple grep -v sans prétraitement sophistiqué devrait suffire, voire mieux. Je suis partisan du principe KISS. Cela vous facilitera la compréhension ou le débogage plus tard. Aussi, sans le tri c'est un peu plus efficace;)

  4. Ceci est purement esthétique mais vous obtiendrez le même résultat avec cette variante légèrement plus courte. :-)

    $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | grep -v $(uname -r | cut -d- -f-2)
    linux-image-3.5.0-44-generic
    linux-image-3.8.0-34-generic
    linux-image-extra-3.5.0-44-generic
    linux-image-extra-3.8.0-34-generic
    

Par conséquent, je me retrouve avec la commande plus simple et plus sûre

$ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | grep -v $(uname -r | cut -d- -f-2) | xargs Sudo apt-get -y purge

Puisque vous voulez réellement nettoyer votre partition /boot, une approche complètement différente consisterait à répertorier le contenu de /boot, à utiliser dpkg -S pour déterminer les packages auxquels les fichiers individuels appartiennent, filtrer ceux qui appartiennent au noyau actuel et supprimer le fichier. les paquets résultants. Mais j'aime mieux votre approche, car elle trouvera également des paquets obsolètes tels que linux-headers-*, qui ne sont pas installés sur /boot, mais sur /usr/src.

24
Malte Skoruppa

J'ai écrit ce script qui supprime les paquets "linux- *" dont la version est inférieure à celle actuellement démarrée. Je pense qu'il n'est pas nécessaire de tester le statut du paquet. La commande demande une confirmation avant de purger les packages. Si vous ne le souhaitez pas, ajoutez l'option -y à la commande apt-get.

Sudo apt-get purge $(dpkg-query -W -f'${Package}\n' 'linux-*' |
sed -nr 's/.*-([0-9]+(\.[0-9]+){2}-[^-]+).*/\1 &/p' | sort -k 1,1V | 
awk '($1==c){exit} {print $2}' c=$(uname -r | cut -f1,2 -d-))

Cependant, pour pouvoir laisser une quantité configurable de noyaux disponibles, je vous recommande d’utiliser mon script linux-purge avec l’option --keep. Voir ici pour plus d'informations sur le script.

5
jarno

TL; DR: aller au bas.

Cependant IS un peu plus longtemps. Je vais le décomposer pour vous:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' Tout comme Malte l'a suggéré. Répertorie les fichiers de noyau pertinents.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Également suggéré par Malte comme moyen plus sûr de ne sélectionner que les fichiers du noyau en recherchant un numéro de version.
  3. Etant donné que nous listons maintenant à la fois les packages image et en-tête, le nom du package peut varier. Nous avons donc cette solution de contournement qui est nécessaire pour le tri awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'. Le résultat est une nouvelle colonne avec le numéro de version précédant le nom du package d'origine, comme ci-dessous:

    $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'
    3.11.0-23 linux-headers-3.11.0-23
    3.11.0-23 linux-headers-3.11.0-23-generic
    3.11.0-24 linux-headers-3.11.0-24
    3.11.0-24 linux-headers-3.11.0-24-generic
    3.11.0-26 linux-headers-3.11.0-26
    3.11.0-26 linux-headers-3.11.0-26-generic
    3.11.0-23 linux-image-3.11.0-23-generic
    3.11.0-24 linux-image-3.11.0-24-generic
    3.11.0-26 linux-image-3.11.0-26-generic
    3.8.0-35 linux-image-3.8.0-35-generic
    3.11.0-23 linux-image-extra-3.11.0-23-generic
    3.11.0-24 linux-image-extra-3.11.0-24-generic
    3.11.0-26 linux-image-extra-3.11.0-26-generic
    3.8.0-35 linux-image-extra-3.8.0-35-generic
    
  4. Nous devons maintenant trier la liste afin d’empêcher la désinstallation d’images plus récentes que celle en cours d’exécution. sort -k1,1 --version-sort -r nous donnant ceci:

    $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r
    3.11.0-26 linux-image-extra-3.11.0-26-generic
    3.11.0-26 linux-image-3.11.0-26-generic
    3.11.0-26 linux-headers-3.11.0-26-generic
    3.11.0-26 linux-headers-3.11.0-26
    3.11.0-24 linux-image-extra-3.11.0-24-generic
    3.11.0-24 linux-image-3.11.0-24-generic
    3.11.0-24 linux-headers-3.11.0-24-generic
    3.11.0-24 linux-headers-3.11.0-24
    3.11.0-23 linux-image-extra-3.11.0-23-generic
    3.11.0-23 linux-image-3.11.0-23-generic
    3.11.0-23 linux-headers-3.11.0-23-generic
    3.11.0-23 linux-headers-3.11.0-23
    3.8.0-35 linux-image-extra-3.8.0-35-generic
    3.8.0-35 linux-image-3.8.0-35-generic
    
  5. Supprimez maintenant les fichiers du noyau actuels et plus récents sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` en nous donnant ceci:

    $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`
    3.11.0-23 linux-image-extra-3.11.0-23-generic
    3.11.0-23 linux-image-3.11.0-23-generic
    3.11.0-23 linux-headers-3.11.0-23-generic
    3.11.0-23 linux-headers-3.11.0-23
    3.8.0-35 linux-image-extra-3.8.0-35-generic
    3.8.0-35 linux-image-3.8.0-35-generic
    
  6. Maintenant, supprimez la première colonne que nous avons ajoutée avec awk '{print $2}' pour obtenir exactement ce que nous voulons:

    $ dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | awk '{print $2}'
    linux-image-extra-3.11.0-23-generic
    linux-image-3.11.0-23-generic
    linux-headers-3.11.0-23-generic
    linux-headers-3.11.0-23
    linux-image-extra-3.8.0-35-generic
    linux-image-3.8.0-35-generic
    
  7. Maintenant, nous pouvons transmettre cela au gestionnaire de paquets pour tout supprimer automatiquement et reconfigurer grub:

    Je vous recommande de commencer par un essai à sec (cependant, pour les besoins de votre script, cela pourrait ne pas être pratique si vous avez un environnement étendu)

    dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | awk '{print $2}' | xargs Sudo apt-get --dry-run remove
    

    Maintenant, si tout semble bien aller, supprimez-le avec:

    dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' | egrep '[0-9]+\.[0-9]+\.[0-9]+' | awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' | sort -k1,1 --version-sort -r | sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"` | awk '{print $2}' | xargs Sudo apt-get -y purge
    

Une fois encore, l’intérêt de ce "one-liner" est de ne supprimer que les noyaux OLDER par rapport au noyau en cours d’exécution (ce qui laisse les noyaux nouvellement installés toujours disponibles).

Merci laissez-moi savoir comment cela fonctionne pour vous et si vous pouviez l'améliorer!

3
user313760

Installez bikeshed (apt install bikeshed) et appelez purge-old-kernels en tant que root.

$ Sudo purge-old-kernels
1
Flow

Vous pouvez simplement lister le répertoire/boot pour voir les versions du noyau que vous avez en utilisant la commande 'ls'. Ensuite, utilisez 'Sudo apt-get -y purge "xxx"', où "xxx" est remplacé par le numéro de version à supprimer. Veillez à ce que ce ne soit pas la version que vous utilisez actuellement !!.

1
Natarajan

Une réponse rapide, explication sur demande:

dpkg -l 'linux-image-[0-9]*' | 
awk -v current="$(uname -r)" '!/^i/ || $2~current {next} {print $2}' |
sed '$d' | 
xargs echo Sudo apt-get autoremove
0
glenn jackman
Sudo dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs Sudo apt-get -y purge

Fonctionne tout le temps, et même Ubuntu 17.10

0
David Ramsay

J'étais vraiment fatigué de toute cette complexité inutile et j'ai créé un paquetage Python qui rend le one-liner trivial:

ubuntu-old-kernel-cleanup | xargs Sudo apt-get -y purge

Installez-le avec

Sudo pip install git+http://github.com/mrts/ubuntu-old-kernel-cleanup.git

Voir plus sur https://github.com/mrts/ubuntu-old-kernel-cleanup .

J'espère que cela aide les autres aussi.

0
mrts