Bash one-liner для удаления только старых ядер

23

Я видел много тем о том, как освободить место в разделе / ​​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}, убедитесь, что я не буду очищать что-либо, связанное с моим текущим ядром
  • Позвоните, чтобы очистить

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

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

Alejandro
источник
Что-то старое из сети: tuxtweaks.com/2010/10/…
user68186
Как вы используете однострочник, если он не сохранен в файле скрипта?
Ярно

Ответы:

25

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

  1. Если вы перечислите все, 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

    Убирая сортировку / сборку, я получаю

    $ 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-*вещи зависят от этих linux-image-*вещей и, следовательно, будут удалены в любом случае, но это не помешает сделать это явным). Во всяком случае, я не вижу смысла в вашей сортировке; простая, 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
источник
Спасибо за ваш ответ @Malte, спасибо за ваш вклад. Я считаю, что ваши первые два шага очень проясняются, и они действительно делают пользователя безопаснее. Тем не менее, я считаю, что ваши последние два шага игнорируют более новые ядра и также очищают их. По крайней мере, я попробовал ваше решение на моем сервере, и оно могло бы удалить что-то нежелательное.
Алехандро
Это интересно. Можете ли вы отправить мне два выхода, один с командой с моим третьим и четвертым предложением, один без них? Плюс вывод uname -r. Для меня это работает нормально. Было бы интересно узнать, почему это не работает в вашем случае.
Malte Skoruppa
1
Я пытался отправить вам сообщение, но я не нашел ни одного адреса электронной почты, поэтому я опубликую свой вывод здесь: hastebin.com/raleyigowe.vhdl uname -r показывает, что мой сервер использует linux-image-3.8.0-34. иногда сервер загрузил новое ядро, но еще не установил его. Вот почему я искал способ удалить только старые ядра.
Алехандро
Эта команда выбрала файл заголовка для моего текущего ядра, что кажется нежелательным.
Марк Стосберг
1
@MalteSkoruppa, uname -rпроизводит 4.8.0-36-generic , который не может исключить linux-headers-4.8.0-36из списка.
Марк Стосберг
7

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

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

Ярно
источник
3

TL; DR: пропустить на дно.

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

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'Так же, как предложил Малте. Перечисляет соответствующие файлы ядра.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Малте также предложил в качестве более безопасного способа выбрать только файлы ядра путем поиска номера версии.
  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

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

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

user313760
источник
Проверьте мой ответ
Ярно
1

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

Натараян
источник
1
Они хотели однострочную команду. Ваше решение требует более 1 строки
Anwar
1

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

$ sudo purge-old-kernels
поток
источник
purge-old-kernels устарела, в пользу «apt autoremove». Если у вас есть проблемы, пожалуйста, сообщите об ошибках в apt. См. Bugs.launchpad.net/bikeshed/+bug/1569228/comments/7
Амеди Ван
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
Гленн Джекман
источник
2
Я предлагаю (или, если хотите, запросить) расширить это, чтобы включить объяснение. :)
Элия ​​Каган
@EliahKagan, я думаю, что сценарий не имеет смысла. Зачем пропускать пакеты, которые нежелательно устанавливать? Сценарий может удалить некоторые более новые ядра, чем текущее, или сохранить несколько старых по sed '$d'команде. Сценарий не удаляет пакеты заголовков linux или другие пакеты, связанные с удаляемыми пакетами ядра, кроме того, он не удаляет файлы конфигурации пакетов. Я бы рекомендовал вместо этого использовать мой ответ.
Ярно
@EliahKagan На самом деле скрипт не удаляет пакеты, а печатает (с помощью echo) apt-getкоманду, которую вы можете запустить.
Ярно
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

Смотрите больше на https://github.com/mrts/ubuntu-old-kernel-cleanup .

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

MRTS
источник
Попробовал это, но я получаю сообщение об ошибке: «ubuntu-old-kernel-cleanup: команда не найдена»
Грант
Тогда его нет в вашем пути поиска исполняемого файла. Вы установили его sudo pip install ...как описано выше? sudoна самом деле важно, иначе pipустановит его в какой-то пользовательский каталог, и оболочка может не искать в этом каталоге исполняемые файлы.
MRTS
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

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

Дэвид Рамсей
источник
Для меня это пытается удалить linux-libc-dev:amd64, что нежелательно.
Malte Skoruppa