Bash однострочный для удаления только старых ядер

21

Я видел много потоков о том, как освободить место на разделе / ​​boot, и это тоже моя цель. Тем не менее, меня интересует только удаление старых ядер, а не каждого из них, но текущего.

Мне нужно, чтобы решение было однострочным, так как я буду запускать скрипт из Puppet, и я не хочу, чтобы вокруг него были дополнительные файлы. До сих пор я получил следующее:

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

Чтобы быть более точным, то, что он делает в данный момент, следующее:

  • Список всех пакетов linux- * и их имена.
  • Перечислите только те, которые имеют номера и сортируют их, возвращая обратный результат. Таким образом, старые ядра перечислены последними.
  • Распечатайте только те результаты, которые идут после текущего ядра
  • Так как есть результаты linux-{image, headers}, убедитесь, что я не буду чистить что-либо, связанное с моим текущим ядром
  • Вызов apt для очистки

Это работает, но я уверен, что решение может быть более элегантным и безопасным для производственной среды, поскольку по меньшей мере 20 из наших серверов запускают Ubuntu.

Спасибо за ваше время, Алехандро.

    
задан Alejandro 07.01.2014 в 16:34
источник

8 ответов

23

Выглядит неплохо, всего несколько комментариев. Два первых комментария делают команду более безопасной, а третья и четвертая делают ее немного короче. Не стесняйтесь следовать или игнорировать любой из них. Хотя я настоятельно советую следовать первым двум. Вы хотите убедиться, что это максимально безопасно. Я имею в виду серьезно. Вы бросаете sudo apt-get -y purge в некоторый автоматически созданный список пакетов. Это так зло ! :)

  1. В листинге all linux-* вы получите много ложных срабатываний, например (пример из моего вывода) linux-sound-base . Несмотря на то, что позже они могут быть отфильтрованы остальной частью вашей команды, я лично почувствовал бы себя более безопасным, не перечисляя их в первую очередь. Лучше контролируйте, какие пакеты вы хотите удалить. Не делайте то, что может иметь неожиданные результаты. Поэтому я начинал с

    dpkg -l linux-{image,headers}-*
    
  2. Ваше регулярное выражение, чтобы «перечислить только те, у которых есть числа», слишком просто, по моему мнению. Например, есть пакет linux-libc-dev:amd64 , когда вы находитесь в 64-битной системе. Ваше регулярное выражение будет соответствовать. Вы не хотите, чтобы он соответствовал. По общему признанию, если вы последовали моему первому совету, то linux-libc-dev:amd64 не будет отображаться в любом случае, но все же. Мы знаем больше о структуре номера версии, чем простой факт «есть число». Кроме того, обычно рекомендуется процитировать регулярные выражения, чтобы предотвратить потенциальные неправильные интерпретации оболочки. Поэтому я бы сделал команду egrep

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
    
  3. Тогда есть эта сортировка. Почему вы сортируете? Так как вы собираетесь удалить все ядра (кроме текущего), важно ли вам удалить старые из них до более новых? Я не думаю, что это имеет значение. Или вы делаете это так, чтобы затем использовать sed для «Печать только результатов, которые идут после текущего ядра»? Но ИМО это слишком сложно. Почему бы просто не отфильтровать результаты, соответствующие вашему текущему ядру, как вы уже делали с grep -v в любом случае, и сделать это? Честно говоря, если я возьму первую часть вашей команды (с моими двумя предыдущими предложениями интегрированы), на моей машине я получаю

    $ 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
    

    Удаление этой сортировки / sed, я получаю

    $ 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
    

    Таким образом, ваша более сложная команда фактически пропустит два пакета на моей машине, которые я хочу удалить (теперь возможно, что эти linux-image-extra-* thingys зависят от linux-image-* thingys и поэтому будут удалены в любом случае, но это может 't больно, чтобы сделать это явным). Во всяком случае, я не вижу смысла в вашей сортировке; простой grep -v без фантастической предварительной обработки должен быть прекрасным, предположительно даже лучше. Я сторонник принципа KISS. Это облегчит вам понимание или отладку позже. Кроме того, без сортировки он немного эффективнее;)

  4. Это чисто эстетично, но вы получите тот же результат с этим чуть более коротким вариантом. : -)

    $ 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
    

Следовательно, я получаю более простую и безопасную команду

$ 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

Поскольку вы действительно хотите очистить свой раздел /boot , совершенно другой подход состоит в том, чтобы перечислить содержимое /boot , используйте dpkg -S для определения пакетов, к которым принадлежат отдельные файлы, отфильтруйте те, которые относятся к текущему ядру и удаляют полученные пакеты. Но мне нравится ваш подход лучше, потому что он также найдет устаревшие пакеты, такие как linux-headers-* , которые не устанавливаются на /boot , а на /usr/src .

    
ответ дан Malte Skoruppa 07.01.2014 в 17:44
5

Я написал этот скрипт, который удаляет пакеты «linux- *», которые имеют меньшую версию, чем загруженный в данный момент. Я думаю, что нет необходимости проверять статус пакета. Команда запрашивает подтверждение перед очисткой пакетов. Если вы этого не хотите, добавьте параметр -y в команду 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-))

Однако, чтобы оставлять настраиваемое количество запасных ядер, я рекомендую использовать мой скрипт linux-purge с опцией --keep . Подробнее о скрипте см. здесь .

    
ответ дан jarno 07.05.2015 в 11:44
3

TL; DR: пропустите снизу.

Это немного дольше. Я сломаю это для вас:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}' Так же, как предложил Малте. Перечисляет соответствующие файлы ядра.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Также предложен Malte как более безопасный способ выбрать только файлы ядра, ища номер версии.
  3. Так как теперь мы, возможно, перечисляем как изображения, так и пакеты заголовков, имена пакетов могут меняться, поэтому у нас есть это обходное решение awk, которое необходимо для сортировки awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}' . Результатом является новый столбец с номером версии до оригинала имя пакета, как показано ниже:

    $ 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. Теперь мы должны отсортировать список, чтобы предотвратить удаление новых изображений, чем тот, который в данный момент запущен. sort -k1,1 --version-sort -r дает нам следующее:

    $ 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. Теперь выделите текущие и более новые файлы ядра sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e 'uname -r | cut -f1,2 -d"-"' , давая нам следующее:

    $ 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. Теперь отмените первый столбец, который мы добавили с помощью awk '{print $2}' , чтобы получить именно то, что мы хотим:

    $ 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. Теперь мы можем передать это менеджеру пакетов, чтобы автоматически удалить все и перенастроить grub:

    Я рекомендую сначала выполнить сухой запуск (хотя для ваших сценариев это может оказаться неприемлемым, если у вас большая среда)

    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
    

    Теперь, если все выглядит хорошо, продолжайте и удалите его с помощью:

    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
    

В очередной раз весь смысл этого «однострочного» заключается в удалении только ядер OLDER, чем текущее запущенное ядро ​​(которое оставляет все вновь установленные ядра еще доступными)

Спасибо, дайте мне знать, как это работает для вас, и если вы можете его улучшить!

    
ответ дан user313760 08.08.2014 в 19:16
1

Вы можете просто перечислить каталог / boot, чтобы увидеть версии ядра, которые вы используете с помощью команды «ls». Затем используйте «sudo apt-get -y purge» xxx », где« xxx »заменяется номером версии, который вы хотите удалить. Позаботьтесь о том, чтобы это была не версия, в которой вы сейчас работаете.

    
ответ дан Natarajan 11.09.2016 в 14:57
1

Установите bikeshed ( apt install bikeshed ) и вызовите purge-old-kernels как root.

$ sudo purge-old-kernels
    
ответ дан Flow 19.12.2016 в 11:38
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

Работает все время и даже ubuntu 17.10

    
ответ дан David Ramsay 25.04.2018 в 08:03
0

Быстрый ответ, пояснение по запросу:

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 08.08.2014 в 20:03
0

Я действительно устал от этой ненужной сложности и создал пакет Python, который делает однострочный тривиальный:

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

Установите его с помощью

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

Подробнее см. Ссылка .

Надеюсь, что это тоже поможет другим.

    
ответ дан mrts 05.10.2015 в 22:54