Bash one-liner per eliminare solo i vecchi kernel


23

Ho visto molti thread su come liberare spazio sulla partizione / boot e anche questo è il mio obiettivo. Tuttavia, mi interessa solo cancellare vecchi kernel e non ognuno di essi, ma quello attuale.

Ho bisogno che la soluzione sia di tipo one-liner poiché eseguirò lo script da Puppet e non voglio avere file extra in giro. Finora ho ottenuto quanto segue:

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

Per essere più precisi, quello che fa al momento è il seguente:

  • Elenca tutti i pacchetti linux- * e stampa i loro nomi.
  • Elenca solo quelli che hanno numeri e li ordina, restituendo il risultato inverso. In questo modo, i kernel più vecchi sono elencati per ultimi.
  • Stampa solo i risultati che seguono il kernel corrente
  • Dato che ci sono alcuni risultati di linux- {image, headers}, assicurati che non eliminerò nulla relativo al mio kernel corrente
  • Chiama apt per eliminare

Funziona, ma sono sicuro che la soluzione può essere più elegante e sicura per un ambiente di produzione, poiché almeno 20 dei nostri server eseguono Ubuntu.

Grazie per il tuo tempo, Alejandro.


Qualcosa di vecchio dalla rete: tuxtweaks.com/2010/10/…
user68186

Come si usa il one-liner, se non viene salvato in un file di script?
jarno

Risposte:


25

Sembra abbastanza carino, solo alcuni commenti. I primi due commenti rendono il comando più sicuro, mentre il terzo e il quarto lo rendono un po 'più breve. Sentiti libero di seguirli o ignorarli. Anche se consiglio vivamente di seguire i primi due. Vuoi assicurarti che sia il più sicuro possibile. Intendo sul serio. Stai lanciando a un sudo apt-get -y purgeelenco di pacchetti generato automaticamente. È così malvagio ! :)

  1. Elencando tutto linux-*otterrai molti falsi positivi, come (esempio dal mio output) linux-sound-base. Anche se questi potrebbero essere filtrati in seguito dal resto del tuo comando, personalmente mi sentirei più sicuro non elencarli in primo luogo. Controlla meglio quali pacchetti vuoi rimuovere. Non fare cose che potrebbero avere risultati inaspettati. Quindi vorrei iniziare con

    dpkg -l linux-{image,headers}-*
  2. La tua regex per "elencare solo quelli che hanno numeri" è leggermente troppo semplice secondo me. Ad esempio, c'è il pacchetto linux-libc-dev:amd64quando ci si trova su un sistema a 64 bit. La tua regex corrisponderà. Non vuoi che corrisponda. Certo, se hai seguito il mio primo consiglio, linux-libc-dev:amd64non verrai comunque elencato, ma comunque. Sappiamo di più sulla struttura di un numero di versione rispetto al semplice fatto "c'è un numero". Inoltre, è generalmente una buona idea citare le regex, solo per evitare potenziali interpretazioni errate da parte della shell. Quindi vorrei eseguire quel comando egrep

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
  3. Poi c'è questa cosa di smistamento. Perché ordini? Dato che rimuoverai comunque tutti i kernel (tranne quello corrente), è importante che rimuova quelli più vecchi prima di quelli nuovi? Non penso che faccia alcuna differenza. O lo stai solo facendo in modo da poter usare sed"Stampa solo i risultati che seguono il kernel corrente"? Ma l'IMO sembra troppo complicato. Perché non semplicemente filtrare i risultati corrispondenti al tuo kernel attuale, come stai già facendo grep -vcomunque, ed essere fatto? Onestamente, se prendo la prima parte del tuo comando (con i miei due precedenti suggerimenti integrati), ottengo sulla mia macchina

    $ 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

    Rimuovendo quella roba di ordinamento / sed, ottengo

    $ 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

    Quindi il tuo comando più complicato in realtà perderebbe due pacchetti sulla mia macchina, che vorrei rimuovere (ora è possibile che quelle linux-image-extra-*cose dipendano dalle linux-image-*cose e quindi vengano rimosse comunque, ma non può far male a renderlo esplicito). Ad ogni modo, non vedo il punto del tuo ordinamento; una grep -vpreelaborazione semplice senza fantasia dovrebbe andare bene, presumibilmente anche meglio. Sono un sostenitore del principio KISS. Ti semplificherà la comprensione o il debug in un secondo momento. Inoltre, senza l'ordinamento è leggermente più efficiente;)

  4. Questo è puramente estetico ma otterrai lo stesso risultato con questa variante leggermente più corta. :-)

    $ 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

Di conseguenza, finisco con il comando più semplice e sicuro

$ 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

Poiché in realtà si desidera ripulire la /bootpartizione, un approccio completamente diverso sarebbe quello di elencare il contenuto /boot, utilizzare dpkg -Sper determinare i pacchetti a cui appartengono i singoli file, filtrare quelli che appartengono al kernel corrente e rimuovere i pacchetti risultanti. Ma mi piace di più il tuo approccio, perché troverà anche pacchetti obsoleti come linux-headers-*, che non vengono installati /boot, ma a /usr/src.


Grazie per la tua risposta @Malte, grazie per il tuo contributo. Trovo che i tuoi primi due passi siano molto chiari e rendono davvero più sicura la linea. Tuttavia, credo che i tuoi ultimi due passi ignorino i kernel più recenti e li eliminino. Almeno, ho provato la tua soluzione su un mio server e avrebbe disinstallato qualcosa di indesiderato.
Alejandro,

Interessante. Potete farmi le due uscite, una con il comando con il mio terzo e quarto suggerimento inclusi, una senza di loro? Più l'output di uname -r. Per me funziona benissimo. Sarebbe interessante vedere perché non funziona nel tuo caso.
Malte Skoruppa,

1
Ho provato a contattarti ma non ho trovato alcun indirizzo e-mail, quindi posterò il mio output qui: hastebin.com/raleyigowe.vhdl uname -r mostra che il mio server sta usando linux-image-3.8.0-34 La cosa è che a volte un server ha scaricato un kernel più recente ma non lo ha ancora installato. Ecco perché stavo cercando un modo per rimuovere solo i vecchi kernel.
Alejandro,

Questo comando ha selezionato il file header per il mio kernel corrente, che sembra indesiderabile.
Mark Stosberg,

1
@MalteSkoruppa, uname -rproduce 4.8.0-36-generic , che non riesce a escludere linux-headers-4.8.0-36dall'elenco.
Mark Stosberg,

7

Ho scritto questo script che rimuove i pacchetti "linux- *" che hanno una versione inferiore a quella attualmente avviata. Penso che non sia necessario testare lo stato del pacchetto. Il comando richiede conferma prima di eliminare i pacchetti. Se non lo desideri, aggiungi l'opzione -y al comando apt-get.

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-))

Tuttavia, per poter lasciare una quantità configurabile di kernel di riserva, consiglio di usare il mio linux-purgescript con l' --keepopzione. Vedi qui per maggiori informazioni sullo script.


3

TL; DR: passa al fondo.

È comunque un po 'più lungo. Lo analizzerò per te:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'Proprio come suggerito da Malte. Elenca i file del kernel rilevanti.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Suggerito anche da Malte come il modo più sicuro per selezionare solo i file del kernel cercando un numero di versione.
  3. Dato che ora stiamo probabilmente elencando sia l'immagine che i pacchetti di intestazione, la denominazione del pacchetto può variare, quindi abbiamo questa soluzione alternativa che è necessaria per l'ordinamento. awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'Il risultato è una nuova colonna con il numero di versione prima del nome del pacchetto originale come di seguito:

    $ 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. Ora dobbiamo ordinare l'elenco per impedire la disinstallazione di eventuali immagini più recenti rispetto a quella attualmente in esecuzione. sort -k1,1 --version-sort -rdandoci questo:

    $ 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. Ora elimina i file del kernel attuali e più recenti sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`dandoci questo:

    $ 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. Ora togli la prima colonna che abbiamo aggiunto awk '{print $2}'per ottenere esattamente ciò che vogliamo:

    $ 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. Ora possiamo inviarlo al gestore dei pacchetti per rimuovere automaticamente tutto e riconfigurare grub:

    Ti consiglio di fare prima una corsa a secco (anche se ai tuoi scopi di scripting questo potrebbe non essere pratico se hai un ambiente di grandi dimensioni)

    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

    Ora, se tutto sembra a posto, vai avanti e rimuovilo con:

    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

Ancora una volta il punto centrale di questo "one-liner" è quello di rimuovere solo i kernel OLDER del kernel attualmente in esecuzione (lasciando tutti i kernel appena installati ancora disponibili)

Grazie fammi sapere come funziona per te e se potresti migliorarlo!


Controlla la mia risposta
jarno

1

Puoi semplicemente elencare la directory / boot per vedere le versioni del kernel che hai usando il comando 'ls'. Quindi utilizzare 'sudo apt-get -y purge "xxx"' dove "xxx" viene sostituito con il numero di versione che si desidera rimuovere. Fai attenzione che non è la versione che stai attualmente eseguendo !!.


1
Volevano un comando da una riga. La tua soluzione ha bisogno di più di 1 riga
Anwar,


0

Una risposta rapida, spiegazione su richiesta:

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

2
Suggerisco (o, se preferisci, richiedi) di ampliarlo per includere la spiegazione. :)
Eliah Kagan,

@EliahKagan, penso che la sceneggiatura non abbia senso. Perché saltare i pacchetti che non si desidera installare? Lo script potrebbe rimuovere alcuni kernel più recenti di quello corrente o salvarne alcuni più vecchi su sed '$d'comando. Lo script non rimuove i pacchetti di intestazione linux o altri pacchetti relativi ai pacchetti del kernel da rimuovere, inoltre non elimina i file di configurazione dei pacchetti. Consiglierei invece di usare la mia risposta.
jarno,

@EliahKagan In realtà lo script non rimuove alcun pacchetto, ma stampa (con echo) il apt-getcomando che potresti eseguire.
jarno,

0

Mi sono davvero stancato di tutta questa inutile complessità e ho creato un pacchetto Python che rende banale il one-liner:

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

Installalo con

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

Scopri di più su https://github.com/mrts/ubuntu-old-kernel-cleanup .

Spero che questo aiuti anche gli altri.


Ho provato questo ma ho ricevuto un errore: "Ubuntu-old-kernel-cleanup: comando non trovato"
Concessione

Quindi non è nel tuo percorso di ricerca eseguibile. L'hai installato sudo pip install ...come descritto sopra? sudoè in realtà importante, altrimenti piplo installerà in alcune directory utente e la shell potrebbe non cercare file eseguibili in questa directory.
sig.

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

Funziona sempre, e persino Ubuntu 17.10


Per me questo cerca di rimuovere linux-libc-dev:amd64, ciò è indesiderato.
Malte Skoruppa,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.