Bash one-liner, aby usunąć tylko stare jądra

23

Widziałem wiele wątków na temat zwolnienia miejsca na partycji / boot i to też jest mój cel. Interesuje mnie jednak tylko usuwanie starych jąder, a nie każdego z nich, ale bieżącego.

Potrzebuję rozwiązania, które będzie jednowierszowe, ponieważ będę uruchamiał skrypt z Puppet i nie chcę mieć żadnych dodatkowych plików. Do tej pory mam następujące:

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

Aby być bardziej precyzyjnym, w tej chwili robi to:

  • Wyświetl listę wszystkich pakietów linux- * i wydrukuj ich nazwy.
  • Wymień tylko te, które mają liczby i posortuj je, zwracając odwrotny wynik. W ten sposób starsze jądra są wymienione na końcu.
  • Wydrukuj tylko wyniki, które pojawią się po bieżącym jądrze
  • Ponieważ istnieje kilka wyników linux- {image, headers}, upewnij się, że nie wyczyszczę niczego związanego z moim bieżącym jądrem
  • Zadzwoń do apt, aby oczyścić

To działa, ale jestem pewien, że rozwiązanie może być bardziej eleganckie i bezpieczne dla środowiska produkcyjnego, ponieważ co najmniej 20 naszych serwerów obsługuje Ubuntu.

Dziękuję za poświęcony czas, Alejandro.

Alejandro
źródło
Coś starego z sieci: tuxtweaks.com/2010/10/…
user68186
Jak korzystać z jednej linijki, jeśli nie jest zapisana w pliku skryptu?
jarno

Odpowiedzi:

25

Wygląda wystarczająco ładnie, tylko kilka komentarzy. Dwa pierwsze komentarze sprawiają, że polecenie jest bezpieczniejsze, a trzeci i czwarty nieco go skracają. Śledź lub zignoruj ​​którekolwiek z nich. Chociaż zdecydowanie zalecam podążanie za pierwszymi dwoma. Chcesz się upewnić, że jest tak bezpieczny, jak to możliwe. Mam na myśli poważnie. Rzucasz sudo apt-get -y purgena automatycznie generowaną listę pakietów. To takie złe ! :)

  1. Lista wszystkich linux-*da ci wiele fałszywych trafień, takich jak (przykład z mojego wyjścia) linux-sound-base. Chociaż mogą one zostać odfiltrowane później przez resztę twojego polecenia, osobiście czułbym się bezpieczniej, nie wymieniając ich w pierwszej kolejności. Lepiej kontroluj, które pakiety chcesz usunąć. Nie rób rzeczy, które mogą mieć nieoczekiwane rezultaty. Więc zacznę od

    dpkg -l linux-{image,headers}-*
  2. Twoje wyrażenie regularne do „listy tylko tych, które mają liczby” jest moim zdaniem nieco zbyt proste. Na przykład pakiet linux-libc-dev:amd64jest dostępny w systemie 64-bitowym. Twoje wyrażenie regularne będzie pasować. Nie chcesz, żeby to pasowało. Trzeba przyznać, że jeśli zastosujesz się do mojej pierwszej rady, i linux-libc-dev:amd64tak nie zostaniesz wymieniony, ale nadal. Wiemy więcej o strukturze numeru wersji niż prosty fakt „istnieje liczba”. Ponadto ogólnie dobrze jest cytować wyrażenia regularne, aby zapobiec potencjalnym błędnym interpretacjom powłoki. Zrobiłbym więc to polecenie egrep

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
  3. Potem jest ta sprawa sortowania. Dlaczego sortujesz Skoro i tak zamierzasz usunąć wszystkie jądra (poza bieżącym), czy ważne jest, aby usunąć starsze przed nowszymi? Nie sądzę, żeby to miało jakąkolwiek różnicę. A może robisz to tylko po to, aby następnie użyć opcji sed„Drukuj tylko te wyniki, które pojawiają się po bieżącym jądrze”? Ale IMO wydaje się to zbyt skomplikowane. Dlaczego nie po prostu odfiltrować wyników odpowiadających bieżącemu jądru, jak już to robisz grep -v, i gotowe? Szczerze mówiąc, jeśli wezmę pierwszą część twojego polecenia (ze zintegrowanymi moimi dwoma poprzednimi sugestiami), otrzymam na moim komputerze

    $ 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

    Usuwam to sortowanie / sed rzeczy, rozumiem

    $ 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

    Tak więc twoje bardziej skomplikowane polecenie faktycznie pominęłoby dwa pakiety na moim komputerze, które chciałbym usunąć (teraz możliwe jest, że te linux-image-extra-*rzeczy zależą od nich linux-image-*i dlatego zostałyby usunięte, ale nie zaszkodzi jawnie to wyrazić). W każdym razie nie widzę sensu twojego sortowania; proste, grep -vbez fantazyjnego przetwarzania wstępnego powinno być w porządku, przypuszczalnie jeszcze lepsze. Jestem zwolenniczką zasady KISS. Ułatwi ci to późniejsze zrozumienie lub debugowanie. Poza tym bez sortowania jest nieco bardziej wydajny;)

  4. Jest to czysto estetyczne, ale uzyskasz taką samą moc wyjściową w tym nieco krótszym wariancie. :-)

    $ 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

W rezultacie otrzymuję prostsze i bezpieczniejsze polecenie

$ 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

Ponieważ naprawdę chcesz wyczyścić /bootpartycję, zupełnie innym podejściem byłoby wylistowanie zawartości /boot, użycie dpkg -Sdo ustalenia pakietów, do których należą poszczególne pliki, odfiltrowanie tych, które należą do bieżącego jądra i usunięcie powstałych pakietów. Ale bardziej podoba mi się twoje podejście, ponieważ znajdzie ono również nieaktualne pakiety, takie jak linux-headers-*, które nie są instalowane /boot, ale do /usr/src.

Malte Skoruppa
źródło
Dziękuję za odpowiedź @Malte, dziękuję za Twój wkład. Uważam, że twoje dwa pierwsze kroki są bardzo jasne i sprawiają, że oneliner rzeczywiście jest bezpieczniejszy. Jednak uważam, że dwa ostatnie kroki ignorują nowsze jądra i również je usuwają. Przynajmniej wypróbowałem twoje rozwiązanie na moim serwerze i odinstalowałbym coś niechcianego.
Alejandro
To interesujące. Czy możesz przesłać mi PM dwa wyjścia, jedno z poleceniem wraz z moją trzecią i czwartą sugestią, jedno bez nich? Plus wydajność uname -r. Dla mnie to działa dobrze. Byłoby ciekawie zobaczyć, dlaczego to nie działa w twoim przypadku.
Malte Skoruppa
1
Próbowałem cię wysłać na PM, ale nie znalazłem żadnego adresu e-mail, więc opublikuję tutaj mój wynik: hastebin.com/raleyigowe.vhdl uname -r pokazuje, że mój serwer używa linux-image-3.8.0-34 czasami serwer pobrał nowsze jądro, ale jeszcze go nie zainstalował. Dlatego szukałem sposobu na usunięcie tylko starych jąder.
Alejandro
To polecenie wybrało plik nagłówka dla mojego obecnego jądra, co wydaje się niepożądane.
Mark Stosberg,
1
@ MalteSkoruppa, uname -rprodukuje 4.8.0-36-generic , co nie wyklucza linux-headers-4.8.0-36z listy.
Mark Stosberg,
7

Napisałem ten skrypt, który usuwa pakiety „linux- *”, które mają wersję mniejszą niż aktualnie uruchomiona. Myślę, że nie jest konieczne testowanie statusu pakietu. Polecenie prosi o potwierdzenie przed czyszczeniem pakietów. Jeśli nie chcesz tego, dodaj opcję -y do komendy 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-))

Jednak, aby móc pozostawić konfigurowalną ilość zapasowych jąder, zalecam użycie mojego linux-purgeskryptu z --keepopcją. Zobacz tutaj, aby uzyskać więcej informacji na temat skryptu.

jarno
źródło
3

TL; DR: przeskocz na dół.

Jest jednak trochę dłużej. Podzielę to dla ciebie:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'Tak jak sugerowała Malte. Wyświetla listę odpowiednich plików jądra.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Sugerowany również przez Malte jako bezpieczniejszy sposób na wybranie tylko plików jądra poprzez wyszukanie numeru wersji.
  3. Ponieważ teraz prawdopodobnie wymieniamy zarówno pakiet obrazu, jak i nagłówka, nazwy pakietów mogą się różnić, dlatego mamy obejście awk, które jest niezbędne do sortowania. awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'W rezultacie powstaje nowa kolumna z numerem wersji przed oryginalną nazwą pakietu, jak poniżej:

    $ 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. Teraz musimy posortować listę, aby zapobiec odinstalowaniu jakichkolwiek nowszych obrazów niż aktualnie uruchomiony. sort -k1,1 --version-sort -rdając nam to:

    $ 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. Teraz usuń bieżące i nowsze pliki jądra, sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`dając nam to:

    $ 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. Teraz zdejmij pierwszą kolumnę, którą dodaliśmy, awk '{print $2}'aby uzyskać dokładnie to, czego chcemy:

    $ 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. Teraz możemy przekazać to do menedżera pakietów, aby automatycznie usunąć wszystko i ponownie skonfigurować grub:

    Najpierw zalecamy wykonanie suchego uruchomienia (chociaż dla celów skryptowych może to nie być praktyczne, jeśli masz duże środowisko)

    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

    Teraz, jeśli wszystko wygląda dobrze, śmiało i usuń to za pomocą:

    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

Po raz kolejny celem tego „jednowierszowego” jest usunięcie tylko jądra OLDER niż aktualnie uruchomione jądro (co pozostawia dostępne nowo zainstalowane jądra)

Dzięki, daj mi znać, jak to działa dla Ciebie i czy możesz to poprawić!

użytkownik313760
źródło
Sprawdź moją odpowiedź
jarno
1

Możesz po prostu wyświetlić katalog / boot, aby zobaczyć wersje jądra, które używasz polecenia „ls”. Następnie użyj „sudo apt-get -y purge” xxx ”, gdzie„ xxx ”jest zastąpione numerem wersji, którą chcesz usunąć. Uważaj, żebyś nie uruchomił wersji !!

Natarajan
źródło
1
Chcieli dowództwa jednej linii. Twoje rozwiązanie wymaga więcej niż 1 linii
Anwar
1

Install bikeshed( apt install bikeshed) i wywołaj purge-old-kernelsjako root.

$ sudo purge-old-kernels
Pływ
źródło
purge-old-kernels został wycofany na korzyść „apt autorove”. Jeśli masz problemy, zgłoś błędy przeciwko apt. Zobacz bugs.launchpad.net/bikeshed/+bug/1569228/comments/7
Amedee Van Gasse
0

Szybka odpowiedź, wyjaśnienie na żądanie:

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
źródło
2
Proponuję (lub, jeśli wolisz, poprosić) o rozwinięcie tego, aby zawierało wyjaśnienie. :)
Eliah Kagan
@EliahKagan, myślę, że skrypt nie ma sensu. Po co pomijać pakiety, których nie należy instalować? Skrypt może usunąć niektóre nowsze jądra niż bieżące lub zapisać niektóre starsze za pomocą sed '$d'polecenia. Skrypt nie usuwa żadnych pakietów nagłówka linux ani innych pakietów związanych z pakietami jądra, które mają zostać usunięte, poza tym nie usuwa plików konfiguracyjnych pakietów. Zamiast tego poleciłbym użyć mojej odpowiedzi.
jarno
@EliahKagan Właściwie skrypt nie usuwa żadnych pakietów, ale wypisuje (przez echo) apt-getpolecenie, które można uruchomić.
jarno
0

Naprawdę zmęczyłem się całą tą niepotrzebną złożonością i stworzyłem pakiet Python, który sprawia, że ​​jedno-liniowy jest trywialny:

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

Zainstaluj za pomocą

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

Zobacz więcej na https://github.com/mrts/ubuntu-old-kernel-cleanup .

Mam nadzieję, że to pomaga również innym.

mrts
źródło
Próbowałem tego, ale pojawia się błąd: „Oczyszczanie jądra starego systemu: nie znaleziono polecenia”
Grant
Zatem nie znajduje się on w ścieżce wyszukiwania wykonywalnego. Czy zainstalowałeś go sudo pip install ...zgodnie z powyższym opisem? sudojest właściwie ważne, w przeciwnym razie pipzainstaluje go w katalogu użytkownika, a powłoka może nie przeszukiwać tego katalogu w poszukiwaniu plików wykonywalnych.
mr.
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

Działa cały czas, a nawet Ubuntu 17.10

David Ramsay
źródło
Dla mnie to próbuje usunąć linux-libc-dev:amd64, co jest niepożądane.
Malte Skoruppa,