Bash one-liner per eliminare solo vecchi kernel

22

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

Ho bisogno che la soluzione sia un one-liner poiché eseguirò la sceneggiatura di Puppet e non voglio avere file extra in giro. Finora ho avuto il seguente:

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, ciò 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 attuale kernel
  • Chiama apt per eliminare

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

Grazie per il tuo tempo, Alejandro.

    
posta Alejandro 07.01.2014 - 16:34

8 risposte

24

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 seguire o ignorare qualcuno di loro. Sebbene raccomanderò vivamente di seguire i primi due. Vuoi assicurarti che sia il più sicuro possibile. Intendo sul serio Stai lanciando un sudo apt-get -y purge in un elenco di pacchetti generato automaticamente. È così male ! :)

  1. L'elenco di tutti linux-* ti darà molti falsi positivi, come (esempio dal mio output) linux-sound-base . Anche se questi potrebbero essere filtrati più tardi 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 possono avere risultati inaspettati. Quindi inizierei con

    dpkg -l linux-{image,headers}-*
    
  2. La tua espressione regolare per "elencare solo quelli che hanno numeri" è leggermente troppo semplice secondo me. Ad esempio, c'è il pacchetto linux-libc-dev:amd64 quando ci si trova su un sistema a 64 bit. Il tuo regex corrisponderà. Tu non vuoi che corrisponda. Certo, se hai seguito il mio primo consiglio, allora linux-libc-dev:amd64 non verrà elencato comunque, ma comunque. Sappiamo di più sulla struttura di un numero di versione del semplice fatto "c'è un numero". Inoltre, è generalmente una buona idea citare regex, solo per evitare potenziali interpretazioni errate da parte della shell. Quindi farei il comando egrep

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
    
  3. Poi c'è questa cosa dell'ordinamento. Perché si ordina? Dato che hai intenzione di rimuovere tutti i kernel (eccetto quello attuale) in ogni caso, è importante rimuovere quelli più vecchi prima di quelli nuovi? Non penso che faccia alcuna differenza. O stai facendo solo così puoi usare sed per "Stampare solo i risultati che seguono il kernel corrente"? Ma questo mi sembra troppo complicato. Perché non filtrare semplicemente i risultati corrispondenti al tuo kernel corrente, come già si fa con grep -v e come si fa? Onestamente, se prendo la prima parte del comando (con i miei due suggerimenti precedenti integrati), sulla mia macchina ottengo

    $ 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
    

    Rimozione di quel materiale 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à mancherebbe due pacchetti sulla mia macchina, che vorrei rimuovere (ora è possibile che quei linux-image-extra-* thingys dipendano dal linux-image-* thingys e quindi vengano rimossi comunque, ma può fa male a renderlo esplicito). Ad ogni modo, non vedo il punto della tua selezione; un semplice grep -v senza preelaborazione elaborata dovrebbe andare bene, presumibilmente anche meglio. Sono un sostenitore del principio KISS. Ti renderà più facile la comprensione o il debug in seguito. 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 più 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

Dato che vuoi effettivamente ripulire la tua partizione /boot , un approccio completamente diverso sarebbe quello di elencare il contenuto di /boot , usare dpkg -S per determinare i pacchetti a cui appartengono i singoli file, filtrare quelli che appartiene al kernel corrente e rimuove i pacchetti risultanti. Ma mi piace il tuo approccio migliore, perché troverà anche pacchetti obsoleti come linux-headers-* , che non vengono installati su /boot , ma su /usr/src .

    
risposta data Malte Skoruppa 07.01.2014 - 17:44
5

Ho scritto questo script che rimuove i pacchetti "linux- *" che hanno una versione minore di quella attualmente avviata. Penso che non sia necessario testare lo stato del pacchetto. Il comando chiede 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}-[^-]+).*/ &/p' | sort -k 1,1V | 
awk '($1==c){exit} {print $2}' c=$(uname -r | cut -f1,2 -d-))

Tuttavia, per poter lasciare la quantità configurabile di kernel di riserva, ti consiglio di utilizzare il mio script linux-purge con l'opzione --keep . Vedi qui per ulteriori informazioni sullo script.

    
risposta data jarno 07.05.2015 - 11:44
3

TL; DR: salta in fondo.

Tuttavia è un po 'più lungo. Lo romperò 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]+' Anche suggerito da Malte come il modo più sicuro per selezionare solo i file del kernel cercando un numero di versione.
  3. Poiché ora stiamo elencando sia l'immagine che i pacchetti di intestazione, la denominazione del pacchetto può variare, quindi abbiamo questa soluzione awk 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 precedente all'originale nome del pacchetto 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 evitare di disinstallare le immagini più recenti di quelle attualmente in esecuzione. sort -k1,1 --version-sort -r 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
    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 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 elimina la prima colonna che abbiamo aggiunto con 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 pacchetti per rimuovere automaticamente tutto e riconfigurare grub:

    Ti consiglio di eseguire prima un ciclo di prova (anche se a scopo 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, procedi 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 l'intero punto di questo "one-liner" è quello di rimuovere solo i kernel OLDER rispetto al kernel attualmente in esecuzione (che lascia ancora disponibili i kernel appena installati)

Grazie, fammi sapere come funziona per te e se puoi migliorarlo!

    
risposta data user313760 08.08.2014 - 19:16
1

Puoi semplicemente elencare la directory / boot per vedere le versioni del kernel che usi 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 sia la versione che stai attualmente utilizzando !!.

    
risposta data Natarajan 11.09.2016 - 14:57
1

Installa bikeshed ( apt install bikeshed ) e chiama purge-old-kernels come utente root.

$ sudo purge-old-kernels
    
risposta data Flow 19.12.2016 - 11:38
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
    
risposta data glenn jackman 08.08.2014 - 20:03
0

Mi sono davvero stancato di tutta questa inutile complessità e ho creato un pacchetto Python che rende banale la 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

Vedi di più sul link .

Spero che questo aiuti anche gli altri.

    
risposta data mrts 05.10.2015 - 22:54
0
sudo dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)//")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*//;/[0-9]/!d' | xargs sudo apt-get -y purge

Funziona sempre, e anche ubuntu 17.10

    
risposta data David Ramsay 25.04.2018 - 08:03

Leggi altre domande sui tag