Bash one-liner para excluir somente kernels antigos

21

Eu vi muitos tópicos sobre como liberar espaço na partição / boot e esse também é meu objetivo. No entanto, estou interessado apenas em excluir os kernels antigos e não em cada um deles, exceto o atual.

Eu preciso da solução para ser um one-liner, já que eu vou rodar o script do Puppet e não quero ter arquivos extras por aí. Até agora eu tenho o seguinte:

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

Para ser mais preciso, o que ele faz no momento é o seguinte:

  • Liste todos os pacotes linux- * e imprima seus nomes.
  • Apenas liste os que possuem números e classifique-os, retornando o resultado inverso. Dessa forma, os kernels mais antigos são listados por último.
  • Imprima apenas os resultados que vão depois do kernel atual
  • Como existem alguns resultados de linux- {image, headers}, certifique-se de não limpar nada relacionado ao meu kernel atual
  • Ligue para o apt para limpar

Isso funciona, mas tenho certeza de que a solução pode ser mais elegante e segura para um ambiente de produção, já que pelo menos 20 dos nossos servidores executam o Ubuntu.

Obrigado pelo seu tempo Alejandro.

    
por Alejandro 07.01.2014 / 16:34

8 respostas

23

Parece bom o suficiente, apenas alguns comentários. Os dois primeiros comentários tornam o comando mais seguro, enquanto o terceiro e o quarto tornam-no um pouco mais curto. Sinta-se à vontade para seguir ou ignorar qualquer um deles. Embora eu recomende strongmente seguir os dois primeiros. Você quer ter certeza de que é o mais seguro possível. Eu quero dizer seriamente. Você está jogando um sudo apt-get -y purge em alguma lista de pacotes gerados automaticamente. Isso é tão mal ! :)

  1. Listar todo o linux-* vai te dar muitos falsos positivos, como (exemplo da minha saída) linux-sound-base . Mesmo que estes possam ser filtrados mais tarde pelo resto do seu comando, eu pessoalmente me sentiria mais seguro não listá-los em primeiro lugar. Melhor controlar quais pacotes você deseja remover. Não faça coisas que possam ter resultados inesperados. Então eu começaria com

    dpkg -l linux-{image,headers}-*
    
  2. Seu regex para "listar apenas os que têm números" é um pouco simples demais na minha opinião. Por exemplo, existe o pacote linux-libc-dev:amd64 quando você está em um sistema de 64 bits. Seu regex vai corresponder. Você não quer que combine. Evidentemente, se você seguiu meu primeiro conselho, então linux-libc-dev:amd64 não será listado de qualquer maneira, mas ainda assim. Sabemos mais sobre a estrutura de um número de versão do que o simples fato de que "há um número". Além disso, geralmente é uma boa ideia citar regexes, apenas para evitar possíveis erros de interpretação pelo shell. Então eu faria o comando egrep

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
    
  3. Depois, há essa coisa de classificação. Por que você classifica? Como você removerá todos os kernels (exceto o atual), é importante para você remover os kernels antes dos mais novos? Eu não acho que faça alguma diferença. Ou você está apenas fazendo isso, então você pode usar sed para "Imprimir apenas os resultados que vão depois do kernel atual"? Mas IMO isso parece muito complicado. Por que não simplesmente filtrar os resultados correspondentes ao seu kernel atual, como você já está fazendo com grep -v , e pronto? Honestamente, se eu pegar a primeira parte do seu comando (com minhas duas sugestões anteriores integradas), na minha máquina eu recebo

    $ 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
    

    Removendo essa classificação / sed, recebo

    $ 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
    

    Assim, seu comando mais complicado perderia dois pacotes em minha máquina, que eu gostaria de remover (agora é possível que esses linux-image-extra-* thingys dependam do linux-image-* thingys e, portanto, sejam removidos de qualquer maneira, mas podem dói para torná-lo explícito). De qualquer forma, não vejo o ponto de sua classificação; um simples grep -v sem pré-processamento sofisticado deve ser bom, presumivelmente ainda melhor. Eu sou um defensor do princípio KISS. Isso tornará mais fácil para você entender ou depurar mais tarde. Além disso, sem a classificação, é um pouco mais eficiente;)

  4. Isso é puramente estético, mas você obterá a mesma saída com essa variante ligeiramente mais curta. : -)

    $ 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
    

Consequentemente, acabo com o comando mais simples e seguro

$ 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

Como você realmente deseja limpar a partição /boot , uma abordagem completamente diferente seria listar o conteúdo de /boot , usar dpkg -S para determinar os pacotes aos quais os arquivos individuais pertencem, filtrar os que são pertencem ao kernel atual e removem os pacotes resultantes. Mas eu gosto mais da sua abordagem, porque ela também encontrará pacotes desatualizados, como linux-headers-* , que não são instalados em /boot , mas em /usr/src .

    
por Malte Skoruppa 07.01.2014 / 17:44
5

Eu escrevi este script que remove os pacotes "linux- *" que possuem uma versão menor que a atualmente inicializada. Eu acho que não é necessário testar o status do pacote. O comando pede confirmação antes de remover os pacotes. Se você não quiser, adicione a opção -y ao 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-))

No entanto, para poder deixar uma quantidade configurável de kernels sobressalentes, recomendo usar meu script linux-purge com a opção --keep . Consulte aqui para obter mais informações sobre o script.

    
por jarno 07.05.2015 / 11:44
3

TL; DR: pule para o final.

É um pouco mais longo. Vou dividir para você:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' Assim como o Malte sugeriu. Lista os arquivos de kernel relevantes.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Também sugerido por Malte como a maneira mais segura de escolher apenas os arquivos do kernel, procurando por um número de versão.
  3. Como agora listamos a imagem e os pacotes de cabeçalho, a nomenclatura do pacote pode variar, portanto, temos essa solução awk necessária para a classificação awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' O resultado é uma nova coluna com o número da versão anterior ao original nome do pacote como abaixo:

    $ 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. Agora, devemos classificar a lista para evitar a desinstalação de imagens mais recentes do que a que está em execução no momento. sort -k1,1 --version-sort -r nos dando isto:

    $ 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. Agora, exclua os arquivos atuais e mais recentes do kernel sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e 'uname -r | cut -f1,2 -d"-"' , fornecendo:

    $ 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. Agora tire a primeira coluna que adicionamos com awk '{print $2}' para obter exatamente o que queremos:

    $ 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. Agora podemos alimentar isso para o gerenciador de pacotes para remover automaticamente tudo e reconfigurar o grub:

    Eu recomendo fazer uma execução seca primeiro (embora, para seus propósitos de script, isso possa não ser prático se você tiver um ambiente grande)

    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
    

    Agora, se tudo estiver bem, vá em frente e remova-o com:

    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
    

Mais uma vez, o objetivo deste "one-liner" é remover apenas os kernels mais antigos que o kernel atualmente em execução (o que deixa os kernels recém-instalados ainda disponíveis)

Obrigado, deixe-me saber como isso funciona para você e se você pode melhorá-lo!

    
por user313760 08.08.2014 / 19:16
1

Você pode simplesmente listar o diretório / boot para ver as versões do kernel que você usa usando o comando 'ls'. Em seguida, use 'sudo apt-get -y purge "xxx"' onde "xxx" é substituído pelo número da versão que você deseja remover. Tome cuidado para que não seja a versão que você está usando atualmente.

    
por Natarajan 11.09.2016 / 14:57
1

Instale bikeshed ( apt install bikeshed ) e chame purge-old-kernels como root.

$ sudo purge-old-kernels
    
por Flow 19.12.2016 / 11:38
0

Uma resposta rápida, explicação a pedido:

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
    
por glenn jackman 08.08.2014 / 20:03
0

Eu me cansei de toda essa complexidade desnecessária e criei um pacote Python que torna o one-liner trivial:

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

Instale-o com

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

Veja mais em link .

Espero que isso ajude os outros também.

    
por 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

Funciona o tempo todo, e até mesmo o ubuntu 17.10

    
por David Ramsay 25.04.2018 / 08:03