Bash satu baris untuk menghapus hanya kernel lama

23

Saya telah melihat banyak utas tentang cara mengosongkan ruang pada partisi / boot dan itulah tujuan saya juga. Namun, saya hanya tertarik menghapus kernel lama dan tidak masing-masing tetapi yang sekarang.

Saya membutuhkan solusi untuk menjadi satu-liner karena saya akan menjalankan skrip dari Puppet dan saya tidak ingin memiliki file tambahan tergeletak di sekitar. Sejauh ini saya mendapat yang berikut:

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

Untuk lebih tepatnya, apa yang dilakukannya saat ini adalah sebagai berikut:

  • Daftar semua paket linux- * dan cetak namanya.
  • Hanya daftar yang memiliki angka dan mengurutkannya, mengembalikan hasil sebaliknya. Dengan cara ini, kernel lama terdaftar terakhir.
  • Cetak hanya hasil yang mengikuti kernel saat ini
  • Karena ada beberapa hasil linux- {image, header}, pastikan saya tidak akan membersihkan apa pun yang berhubungan dengan kernel saya saat ini
  • Panggil apt untuk membersihkan

Ini berfungsi, tapi saya yakin solusinya bisa lebih elegan dan aman untuk lingkungan produksi, karena setidaknya 20 server kami menjalankan Ubuntu.

Terima kasih untuk waktumu, Alejandro.

Alejandro
sumber
Sesuatu yang lama dari Internet: tuxtweaks.com/2010/10/…
user68186
Bagaimana Anda menggunakan one-liner Anda, jika tidak disimpan dalam file skrip?
jarno

Jawaban:

25

Terlihat cukup bagus, hanya beberapa komentar. Dua komentar pertama membuat perintah lebih aman, sedangkan yang ketiga dan keempat membuatnya sedikit lebih pendek. Jangan ragu untuk mengikuti atau mengabaikan salah satu dari mereka. Padahal saya akan sangat menyarankan untuk mengikuti dua yang pertama. Anda ingin memastikan itu seaman mungkin. Maksud saya serius. Anda melempar sudo apt-get -y purgepada beberapa daftar paket yang dibuat secara otomatis. Itu sangat jahat ! :)

  1. Cantumkan semua linux-* akan membuat Anda mendapatkan banyak kesalahan positif, seperti (contoh dari hasil saya) linux-sound-base. Meskipun ini dapat disaring kemudian oleh perintah Anda, saya pribadi akan merasa lebih aman untuk tidak mendaftarkannya di tempat pertama. Lebih baik kontrol paket apa yang ingin Anda hapus. Jangan lakukan hal-hal yang mungkin memiliki hasil yang tidak terduga. Jadi saya akan mulai dengan

    dpkg -l linux-{image,headers}-*
  2. Regex Anda untuk "daftar hanya yang memiliki angka" sedikit terlalu sederhana menurut saya. Misalnya ada paketlinux-libc-dev:amd64 ketika Anda menggunakan sistem 64-bit. Regex Anda akan cocok. Anda tidak ingin itu cocok. Memang, jika Anda mengikuti saran pertama saya, maka linux-libc-dev:amd64tidak akan terdaftar, tapi tetap saja. Kami tahu lebih banyak tentang struktur nomor versi daripada fakta sederhana "ada nomor". Selain itu, umumnya adalah ide yang baik untuk mengutip regex, hanya untuk mencegah kesalahan interpretasi oleh shell. Jadi saya akan membuat perintah egrep itu

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
  3. Lalu ada hal semacam ini. Mengapa Anda menyortir? Karena Anda akan menghapus semua kernel (kecuali yang sekarang), apakah penting bagi Anda untuk menghapus yang lebih lama sebelum yang lebih baru? Saya tidak berpikir itu membuat perbedaan. Atau apakah Anda hanya melakukan itu sehingga Anda dapat menggunakannyased untuk "Hanya mencetak hasil yang mengikuti kernel saat ini"? Tapi IMO ini terasa terlalu rumit. Mengapa tidak hanya menyaring hasil yang sesuai dengan kernel Anda saat ini, seperti yang sudah Anda lakukan dengan grep -v, dan dilakukan? Jujur, jika saya mengambil bagian pertama dari perintah Anda (dengan dua saran saya sebelumnya terintegrasi), di komputer saya saya dapatkan

    $ 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

    Menghapus hal penyortiran / sed, saya dapatkan

    $ 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

    Jadi perintah Anda yang lebih rumit sebenarnya akan melewatkan dua paket di mesin saya, yang ingin saya hapus (sekarang mungkin saja itu linux-image-extra-* hal itu bergantung pada hal- linux-image-*hal dan karenanya akan dihapus, tetapi tidak ada salahnya untuk membuatnya eksplisit). Bagaimanapun, saya tidak melihat titik penyortiran Anda; sederhana grep -vtanpa preprocessing mewah harus baik-baik saja, mungkin bahkan lebih baik. Saya seorang pendukung prinsip KISS. Ini akan membuat Anda lebih mudah untuk memahami atau men-debug nanti. Juga, tanpa penyortiran, ini sedikit lebih efisien;)

  4. Ini murni aestetik tetapi Anda akan mendapatkan hasil yang sama dengan varian yang sedikit lebih pendek ini. :-)

    $ 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

Akibatnya, saya berakhir dengan perintah yang lebih sederhana dan lebih aman

$ 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

Karena Anda benar-benar ingin membersihkan /bootpartisi Anda , pendekatan yang sama sekali berbeda adalah dengan membuat daftar isi /boot, gunakan dpkg -Suntuk menentukan paket-paket yang dimiliki oleh masing-masing file, memfilter yang termasuk dalam kernel saat ini, dan menghapus paket-paket yang dihasilkan. Tapi saya lebih suka pendekatan Anda, karena juga akan menemukan paket-paket usang seperti linux-headers-*, yang tidak diinstal /boot, tetapi untuk /usr/src.

Malte Skoruppa
sumber
Terima kasih atas tanggapan Anda @ Malte, terima kasih atas masukan Anda. Saya menemukan dua langkah pertama Anda sangat mengklarifikasi dan membuat oneliner lebih aman. Namun, saya percaya dua langkah terakhir Anda mengabaikan kernel yang lebih baru dan membersihkannya juga. Setidaknya, saya mencoba solusi Anda di server saya dan itu akan menghapus sesuatu yang tidak diinginkan.
Alejandro
Itu menarik. Dapatkah Anda memberi saya PM dua output, satu dengan perintah dengan saran ketiga dan keempat saya termasuk, satu tanpa mereka? Ditambah output dari uname -r. Bagi saya itu berfungsi dengan baik. Akan menarik untuk melihat mengapa itu tidak berhasil dalam kasus Anda.
Malte Skoruppa
1
Saya mencoba untuk PM Anda tetapi saya tidak menemukan alamat email sehingga saya akan memposting output saya di sini: hastebin.com/raleyigowe.vhdl uname -r menunjukkan server saya menggunakan linux-image-3.8.0-34 Masalahnya adalah bahwa terkadang server telah mengunduh kernel yang lebih baru tetapi belum menginstalnya. Itu sebabnya saya mencari cara untuk menghapus hanya kernel lama.
Alejandro
Perintah ini memilih file header untuk kernel saya saat ini, yang tampaknya tidak diinginkan.
Mark Stosberg
1
@Malte Scoreuppa, uname -rmenghasilkan 4.8.0-36-generic , yang gagal untuk mengecualikan linux-headers-4.8.0-36dari daftar.
Mark Stosberg
7

Saya menulis skrip ini yang menghapus paket "linux- *" yang memiliki versi lebih rendah daripada yang saat ini di-boot. Saya pikir tidak perlu menguji status paket. Perintah meminta konfirmasi sebelum membersihkan paket. Jika Anda tidak menginginkannya, tambahkan opsi -y ke perintah 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-))

Namun, untuk dapat meninggalkan jumlah kernel cadangan yang dapat dikonfigurasi, saya sarankan untuk menggunakan linux-purgeskrip saya dengan --keepopsi. Lihat di sini untuk informasi lebih lanjut tentang skrip.

jarno
sumber
3

TL; DR: lompat ke bawah.

Ini sedikit lebih lama. Saya akan memecahnya untuk Anda:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'Seperti yang disarankan Malte. Daftar file-file kernel yang relevan.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Juga disarankan oleh Malte sebagai cara yang lebih aman untuk memilih hanya file-file kernel dengan mencari nomor versi.
  3. Karena sekarang kami mungkin mencantumkan paket gambar dan header, penamaan paket dapat bervariasi sehingga kami memiliki solusi awk yang diperlukan untuk pengurutan awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'. Hasilnya adalah kolom baru dengan nomor versi sebelum nama paket asli seperti di bawah ini:

    $ 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. Sekarang kita harus mengurutkan daftar untuk mencegah mencopot pemasangan gambar yang lebih baru daripada yang sedang berjalan. sort -k1,1 --version-sort -rmemberi kami ini:

    $ 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. Sekarang hapus file kernel saat ini dan yang lebih baru yang sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`memberi kami ini:

    $ 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. Sekarang lepaskan kolom pertama yang kita tambahkan awk '{print $2}'untuk mendapatkan apa yang kita inginkan:

    $ 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. Sekarang kita dapat memasukkan itu ke manajer paket untuk secara otomatis menghapus semuanya dan mengkonfigurasi ulang grub:

    Saya sarankan melakukan dry run terlebih dahulu (meskipun untuk keperluan skrip Anda ini mungkin tidak praktis jika Anda memiliki lingkungan yang besar)

    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

    Sekarang jika semuanya terlihat bagus, silakan hapus dengan:

    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

Sekali lagi inti dari "one-liner" ini adalah untuk menghapus hanya kernel yang LEBIH TUA dari kernel yang saat ini berjalan (yang membuat kernel yang baru diinstal masih tersedia)

Terima kasih beri tahu saya bagaimana ini bekerja untuk Anda dan jika Anda dapat memperbaikinya!

pengguna313760
sumber
Lihat jawaban
jarno
1

Anda cukup daftar direktori / boot untuk melihat versi kernel yang Anda miliki menggunakan perintah 'ls'. Kemudian gunakan 'sudo apt-get -y purge "xxx"' di mana "xxx" diganti dengan nomor versi yang ingin Anda hapus. Berhati-hatilah karena ini bukan versi yang sedang Anda jalankan !!.

Natarajan
sumber
1
Mereka menginginkan perintah satu baris. Solusi Anda membutuhkan lebih dari 1 baris
Anwar
1

Instal bikeshed( apt install bikeshed) dan panggil purge-old-kernelssebagai root.

$ sudo purge-old-kernels
Mengalir
sumber
kernel purge-old-sudah usang, mendukung "apt autoremove". Jika Anda memiliki masalah, harap ajukan bug ke apt. Lihat bugs.launchpad.net/bikeshed/+bug/1569228/comments/7
Amedee Van Gasse
0

Jawaban cepat, penjelasan atas permintaan:

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
sumber
2
Saya menyarankan (atau, jika Anda mau, meminta) memperluas ini untuk memasukkan penjelasan. :)
Eliah Kagan
@EliahKagan, saya pikir naskahnya tidak masuk akal. Mengapa melewatkan paket yang tidak diinginkan untuk diinstal? Script mungkin menghapus beberapa kernel yang lebih baru dari yang sekarang, atau menyimpan yang lebih tua dengan sed '$d'perintah. Skrip tidak menghapus paket linux-header atau paket lain yang terkait dengan paket kernel yang akan dihapus, selain itu tidak menghapus file konfigurasi paket. Saya akan merekomendasikan menggunakan jawaban saya, sebagai gantinya.
jarno
@EliahKagan actally script tidak menghapus paket, tapi cetakan (oleh echo) yang apt-getperintah yang Anda dapat menjalankan.
jarno
0

Saya benar-benar bosan dengan semua kerumitan yang tidak perlu ini dan membuat paket Python yang membuat sepele satu-baris:

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

Instal dengan

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

Lihat lebih lanjut di https://github.com/mrts/ubuntu-old-kernel-cleanup .

Semoga ini bisa membantu orang lain juga.

Tuan
sumber
Mencoba ini, tetapi saya mendapatkan kesalahan: "ubuntu-old-kernel-cleanup: command not found"
Grant
Maka itu tidak ada di jalur pencarian Anda yang dapat dieksekusi. Apakah Anda menginstalnya sudo pip install ...seperti yang dijelaskan di atas? sudosebenarnya penting, jika tidak pipakan menginstalnya di beberapa direktori pengguna dan shell mungkin tidak mencari direktori ini untuk file yang dapat dieksekusi.
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

Bekerja setiap saat, dan bahkan ubuntu 17.10

David Ramsay
sumber
Bagi saya ini mencoba untuk menghapus linux-libc-dev:amd64, itu tidak diinginkan.
Malte Skoruppa