Bash One-Liner, um nur alte Kernel zu löschen

23

Ich habe viele Threads zum Freigeben von Speicherplatz auf der / boot-Partition gesehen, und das ist auch mein Ziel. Ich bin jedoch nur daran interessiert, alte Kernel zu löschen und nicht jeden von ihnen, sondern den aktuellen.

Ich brauche die Lösung, um ein Einzeiler zu sein, da ich das Skript von Puppet ausführen und keine zusätzlichen Dateien haben möchte. Bisher habe ich folgendes bekommen:

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

Genauer gesagt ist das, was es im Moment tut, das Folgende:

  • Listet alle Linux- * Pakete auf und druckt deren Namen aus.
  • Listen Sie nur diejenigen auf, die Zahlen haben, und sortieren Sie sie, und geben Sie das umgekehrte Ergebnis zurück. Auf diese Weise werden ältere Kernel zuletzt aufgelistet.
  • Nur die Ergebnisse ausgeben, die nach dem aktuellen Kernel liegen
  • Da es einige linux- {image, headers} -Ergebnisse gibt, stelle sicher, dass ich nichts lösche, was mit meinem aktuellen Kernel zusammenhängt
  • Rufen Sie apt zum Löschen an

Das funktioniert, aber ich bin mir sicher, dass die Lösung eleganter und sicherer für eine Produktionsumgebung ist, da mindestens 20 unserer Server Ubuntu ausführen.

Danke für deine Zeit, Alejandro.

Alejandro
quelle
Etwas Altes aus dem Netz: tuxtweaks.com/2010/10/…
user68186
Wie verwenden Sie Ihren Einzeiler, wenn er nicht in einer Skriptdatei gespeichert ist?
jarno

Antworten:

25

Sieht gut aus, nur ein paar Kommentare. Die beiden ersten Kommentare machen den Befehl sicherer, während der dritte und vierte ihn etwas kürzer machen. Fühlen Sie sich frei, einem von ihnen zu folgen oder ihn zu ignorieren. Ich rate jedoch dringend, den ersten beiden zu folgen. Sie möchten sicherstellen, dass es so sicher wie möglich ist. Ich meine, ernsthaft. Sie werfen eine sudo apt-get -y purgeautomatisch generierte Paketliste auf. Das ist so böse ! :)

  1. Wenn Sie alle linux-*auflisten, erhalten Sie viele Fehlalarme, z. B. (Beispiel aus meiner Ausgabe) linux-sound-base. Auch wenn diese möglicherweise später vom Rest Ihres Kommandos herausgefiltert werden, würde ich mich persönlich sicherer fühlen, wenn Sie sie nicht an erster Stelle aufführen. Kontrollieren Sie besser, welche Pakete Sie entfernen möchten. Tun Sie keine Dinge, die zu unerwarteten Ergebnissen führen können. Also würde ich anfangen mit

    dpkg -l linux-{image,headers}-*
  2. Ihre Regex, "nur diejenigen aufzulisten, die Zahlen haben", ist meiner Meinung nach etwas zu einfach. Zum Beispiel gibt es das Paket, linux-libc-dev:amd64wenn Sie sich auf einem 64-Bit-System befinden. Ihr regulärer Ausdruck wird passen. Du willst nicht, dass es zusammenpasst. Zugegeben, wenn Sie meinen ersten Rat befolgt haben, werden Sie linux-libc-dev:amd64trotzdem nicht aufgelistet, aber trotzdem. Wir wissen mehr über die Struktur einer Versionsnummer als über die einfache Tatsache, dass es eine Nummer gibt. Darüber hinaus ist es im Allgemeinen eine gute Idee, reguläre Ausdrücke zu zitieren, um mögliche Fehlinterpretationen durch die Shell zu vermeiden. Also würde ich diesen egrep-Befehl ausführen

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
  3. Dann ist da noch dieses Sortierding. Warum sortierst du? Ist es für Sie wichtig, ältere Kernel vor neueren zu entfernen, da Sie ohnehin alle Kernel (außer den aktuellen) entfernen werden? Ich denke nicht, dass es einen Unterschied macht. Oder machen Sie das nur, damit Sie sed"nur die Ergebnisse ausgeben können, die nach dem aktuellen Kernel liegen"? Aber IMO fühlt sich das viel zu kompliziert an. Warum nicht einfach die Ergebnisse herausfiltern, die Ihrem aktuellen Kernel entsprechen, wie Sie es grep -vohnehin schon tun , und fertig? Ehrlich gesagt, wenn ich den ersten Teil Ihres Befehls (mit meinen beiden vorherigen Vorschlägen integriert) auf meinem Computer nehme, erhalte ich

    $ 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

    Wenn ich das Sortier- / Sed-Zeug entferne, verstehe ich

    $ 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

    Ihr komplizierterer Befehl würde also tatsächlich zwei Pakete auf meinem Computer vermissen, die ich entfernen möchte (jetzt ist es möglich, dass diese linux-image-extra-*Dings von den Dings abhängen linux-image-*und daher trotzdem entfernt werden, aber es kann nicht schaden, es explizit zu machen). Ich sehe jedenfalls nicht den Sinn Ihrer Sortierung; Eine einfache, grep -vausgefallene Vorverarbeitung sollte in Ordnung sein, vermutlich sogar noch besser. Ich bin ein Befürworter des KISS-Prinzips. Dies erleichtert Ihnen das spätere Verstehen oder Debuggen. Auch ohne die Sortierung ist es etwas effizienter;)

  4. Dies ist rein ästhetisch, aber mit dieser etwas kürzeren Variante erhalten Sie die gleiche Ausgabe. :-)

    $ 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

Folglich komme ich zu dem einfacheren und sichereren Befehl

$ 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

Da Sie tatsächlich Ihre bereinigen möchten /bootPartition, würde einen völlig anderen Ansatz sein , den Inhalt aufzulisten /boot, verwenden Sie dpkg -Sdie Pakete , um festzustellen , dass die einzelnen Dateien gehören, ausfiltern diejenigen, die mit dem aktuellen Kernel gehören, und die daraus resultierenden Pakete entfernen. Aber ich mag Ihren Ansatz besser, weil er auch veraltete Pakete findet linux-headers-*, die nicht auf /boot, sondern auf installiert werden /usr/src.

Malte Skoruppa
quelle
Danke für deine Antwort @Malte, danke für deinen Input. Ich finde Ihre beiden ersten Schritte sehr klar und sie machen den Oneliner in der Tat sicherer. Ich glaube jedoch, dass Ihre beiden letzten Schritte die neueren Kernel ignorieren und sie auch bereinigen. Zumindest habe ich Ihre Lösung auf einem Server von mir ausprobiert und etwas Unerwünschtes deinstalliert.
Alejandro
Das ist interessant. Können Sie mir die beiden Ausgaben per PM senden, eine mit dem Befehl mit meinem dritten und vierten Vorschlag, eine ohne sie? Plus die Ausgabe von uname -r. Bei mir funktioniert es gut. Es wäre interessant zu sehen, warum es in Ihrem Fall nicht funktioniert.
Malte Skoruppa
1
Ich habe versucht, Ihnen eine PM zu senden, aber ich habe keine E-Mail-Adresse gefunden. Deshalb werde ich meine Ausgabe hier veröffentlichen: hastebin.com/raleyigowe.vhdl uname -r zeigt an, dass mein Server linux-image-3.8.0-34 verwendet Manchmal hat ein Server einen neueren Kernel heruntergeladen, aber noch nicht installiert. Deshalb habe ich nach einer Möglichkeit gesucht, nur alte Kernel zu entfernen .
Alejandro
Dieser Befehl hat die Header-Datei für meinen aktuellen Kernel ausgewählt, was unerwünscht erscheint.
Mark Stosberg
1
@MalteSkoruppa, uname -rproduziert 4.8.0-36-generic , was nicht linux-headers-4.8.0-36aus der Liste ausschließt.
Mark Stosberg
7

Ich habe dieses Skript geschrieben, das "linux- *" - Pakete entfernt, deren Version niedriger ist als die derzeit gebootete. Ich denke, es ist nicht notwendig, den Paketstatus zu testen. Der Befehl fordert eine Bestätigung an, bevor Pakete gelöscht werden. Wenn Sie das nicht möchten, fügen Sie dem Befehl apt-get die Option -y hinzu.

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

Um jedoch eine konfigurierbare Anzahl von Ersatzkernen zu belassen, empfehle ich, mein linux-purgeSkript mit --keepOption zu verwenden. Sehen Sie hier für weitere Informationen über das Drehbuch.

jarno
quelle
3

TL; DR: nach unten springen.

Es ist allerdings ein bisschen länger. Ich werde es für Sie aufschlüsseln:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'Genau wie Malte vorgeschlagen hat. Listet die relevanten Kerneldateien auf.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Auch von Malte als sicherer Weg vorgeschlagen, nur die Kerneldateien herauszusuchen, indem man nach einer Versionsnummer sucht.
  3. Da wir jetzt möglicherweise sowohl das Image- als auch das Header-Paket auflisten, kann die Paketbezeichnung variieren, sodass wir diese Problemumgehung haben, die für die Sortierung erforderlich ist. awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'Das Ergebnis ist eine neue Spalte mit der Versionsnummer vor dem ursprünglichen Paketnamen wie folgt:

    $ 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. Jetzt müssen wir die Liste sortieren, um zu verhindern, dass neuere als die derzeit ausgeführten Images deinstalliert werden. sort -k1,1 --version-sort -rgib uns das:

    $ 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. Entfernen Sie nun die aktuellen und neueren Kerneldateien und sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`geben Sie uns Folgendes:

    $ 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. Entfernen Sie nun die erste Spalte, mit der wir hinzugefügt haben awk '{print $2}', um genau das zu erhalten, was wir wollen:

    $ 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. Jetzt können wir das an den Paketmanager weiterleiten, um automatisch alles zu entfernen und grub neu zu konfigurieren:

    Ich empfehle, zuerst einen Probelauf durchzuführen (obwohl dies für Ihre Skripterstellung unter Umständen nicht sinnvoll ist, wenn Sie eine große Umgebung haben).

    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

    Nun, wenn alles gut aussieht, entferne es mit:

    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

Wieder einmal besteht der Sinn dieses "One-Liner" darin, nur den Kernel zu entfernen, der ÄLTER ist als der derzeit ausgeführte Kernel (wodurch alle neu installierten Kernel noch verfügbar sind).

Danke, lass mich wissen, wie das bei dir funktioniert und ob du es verbessern könntest!

user313760
quelle
Überprüfe meine Antwort
jarno
1

Sie können einfach das Verzeichnis / boot auflisten, um die Kernel-Versionen anzuzeigen, die Sie mit dem Befehl 'ls' haben. Verwenden Sie dann 'sudo apt-get -y purge "xxx"', wobei "xxx" durch die Versionsnummer ersetzt wird, die Sie entfernen möchten. Achten Sie darauf, dass es sich nicht um die Version handelt, die Sie gerade ausführen.

Natarajan
quelle
1
Sie wollten ein einzeiliges Kommando. Ihre Lösung benötigt mehr als 1 Zeile
Anwar
1

Installiere bikeshed( apt install bikeshed) und rufe purge-old-kernelsals root auf.

$ sudo purge-old-kernels
Fließen
quelle
purge-old-kernels wurde zugunsten von "apt autoremove" verworfen. Wenn Sie Probleme haben, melden Sie bitte Fehler gegen apt. Siehe bugs.launchpad.net/bikeshed/+bug/1569228/comments/7
Amedee Van Gasse
0

Eine schnelle Antwort, Erklärung auf Anfrage:

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
Glenn Jackman
quelle
2
Ich schlage vor (oder, wenn Sie es vorziehen, bitte), dies um die Erklärung zu erweitern. :)
Eliah Kagan
@EliahKagan, ich finde das Drehbuch nicht sinnvoll. Warum Pakete überspringen, die nicht installiert werden sollen? Das Skript entfernt möglicherweise einige neuere Kernel als den aktuellen oder speichert einen älteren Kernel per sed '$d'Befehl. Das Skript entfernt keine Linux-Header-Pakete oder andere Pakete, die sich auf die zu entfernenden Kernel-Pakete beziehen, und löscht auch keine Konfigurationsdateien der Pakete. Ich würde stattdessen empfehlen, meine Antwort zu verwenden.
15.
@EliahKagan Tatsächlich entfernt das Skript keine Pakete, sondern druckt (durch echo) den apt-getBefehl, den Sie ausführen könnten.
15.
0

Ich habe die ganze unnötige Komplexität satt und ein Python-Paket erstellt, das den Einzeiler trivial macht:

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

Installieren Sie es mit

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

Weitere Informationen finden Sie unter https://github.com/mrts/ubuntu-old-kernel-cleanup .

Hoffe das hilft auch anderen.

mrts
quelle
Versuchte dies, aber ich bekomme die Fehlermeldung: "Ubuntu-alten-Kernel-Bereinigung: Befehl nicht gefunden"
Grant
Dann ist es nicht in Ihrem ausführbaren Suchpfad. Hast du es sudo pip install ...wie oben beschrieben installiert ? sudoist eigentlich wichtig, sonst pipwird es in einem Benutzerverzeichnis installiert und die Shell durchsucht dieses Verzeichnis möglicherweise nicht nach ausführbaren Dateien.
Mrts
0
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

Funktioniert die ganze Zeit und sogar Ubuntu 17.10

David Ramsay
quelle
Für mich versucht dies zu entfernen linux-libc-dev:amd64, das ist unerwünscht.
Malte Skoruppa