Bash one-liner để chỉ xóa các hạt nhân cũ


23

Tôi đã thấy rất nhiều chủ đề về cách giải phóng không gian trên phân vùng / boot và đó cũng là mục tiêu của tôi. Tuy nhiên, tôi chỉ quan tâm đến việc xóa các hạt nhân và không phải mỗi một trong số chúng mà là hiện tại.

Tôi cần giải pháp để trở thành một lớp lót vì tôi sẽ chạy tập lệnh từ Puppet và tôi không muốn có thêm các tập tin nằm xung quanh. Cho đến nay tôi đã nhận được như sau:

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

Nói chính xác hơn, những gì nó làm vào lúc này là như sau:

  • Liệt kê tất cả các gói linux- * và in tên của chúng.
  • Chỉ liệt kê những cái có số và sắp xếp chúng, trả về kết quả ngược lại. Bằng cách này, hạt nhân cũ hơn được liệt kê cuối cùng.
  • Chỉ in các kết quả đi sau kernel hiện tại
  • Vì có một số kết quả linux- {image, headers}, hãy đảm bảo tôi sẽ không xóa bất cứ thứ gì liên quan đến kernel hiện tại của tôi
  • Gọi apt để thanh trừng

Điều này hoạt động, nhưng tôi chắc rằng giải pháp có thể thanh lịch hơn và nó an toàn cho môi trường sản xuất, vì ít nhất 20 máy chủ của chúng tôi chạy Ubuntu.

Cảm ơn thời gian của bạn, Alejandro.


Một cái gì đó cũ từ Net: tuxtweaks.com/2010/10/ Lời
user68186

Làm thế nào để bạn sử dụng một lớp lót của bạn, nếu nó không được lưu trong một tập tin kịch bản?
jarno

Câu trả lời:


25

Trông đủ đẹp, chỉ cần một vài bình luận. Hai bình luận đầu tiên làm cho lệnh an toàn hơn, trong khi ý kiến ​​thứ ba và thứ tư làm cho nó ngắn hơn một chút. Hãy theo dõi hoặc bỏ qua bất kỳ một trong số họ. Mặc dù tôi sẽ khuyên mạnh mẽ để làm theo hai đầu tiên. Bạn muốn chắc chắn rằng nó an toàn nhất có thể. Ý tôi là nghiêm túc Bạn đang ném một sudo apt-get -y purgesố danh sách gói được tạo tự động. Điều đó thật là xấu xa ! :)

  1. Liệt kê tất cả linux-*sẽ giúp bạn có nhiều thông tin sai, chẳng hạn như (ví dụ từ đầu ra của tôi) linux-sound-base. Mặc dù những thứ này có thể được lọc ra sau đó bởi phần còn lại của lệnh của bạn, cá nhân tôi sẽ cảm thấy an toàn hơn khi không liệt kê chúng ở vị trí đầu tiên. Kiểm soát tốt hơn những gói bạn muốn loại bỏ. Đừng làm những việc có thể có kết quả bất ngờ. Vì vậy, tôi sẽ bắt đầu với

    dpkg -l linux-{image,headers}-*
  2. Theo tôi, biểu thức regex của bạn để "chỉ liệt kê những cái có số" là hơi quá đơn giản. Chẳng hạn, có gói linux-libc-dev:amd64khi bạn sử dụng hệ thống 64 bit. Regex của bạn sẽ phù hợp. Bạn không muốn nó phù hợp. Phải thừa nhận rằng, nếu bạn làm theo lời khuyên đầu tiên của tôi, thì linux-libc-dev:amd64dù sao cũng sẽ không được liệt kê, nhưng vẫn vậy. Chúng tôi biết nhiều hơn về cấu trúc của một số phiên bản hơn là thực tế đơn giản "có một số". Ngoài ra, nói chung là một ý tưởng tốt để trích dẫn các biểu thức chính tả, chỉ để ngăn chặn các giải thích sai tiềm năng bằng vỏ. Vì vậy, tôi sẽ thực hiện lệnh egrep đó

     egrep '[0-9]+\.[0-9]+\.[0-9]+'
  3. Sau đó, có điều sắp xếp này. Tại sao bạn sắp xếp? Vì dù sao bạn cũng sẽ loại bỏ tất cả các hạt nhân (ngoại trừ hạt nhân hiện tại), điều quan trọng đối với bạn là loại bỏ những cái cũ hơn trước những cái mới hơn? Tôi không nghĩ rằng nó làm cho bất kỳ sự khác biệt. Hoặc bạn chỉ đang làm điều đó để sau đó bạn có thể sử dụng sedđể "Chỉ in các kết quả đi sau kernel hiện tại"? Nhưng IMO điều này cảm thấy quá phức tạp. Tại sao không chỉ đơn giản là lọc ra các kết quả tương ứng với kernel hiện tại của bạn, như bạn vẫn đang làm với grep -vdù sao, và được thực hiện? Thành thật mà nói, nếu tôi thực hiện phần đầu tiên của lệnh của bạn (với hai đề xuất trước đây của tôi được tích hợp), trên máy của tôi, tôi nhận được

    $ 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

    Loại bỏ thứ sắp xếp / sed đó, tôi nhận được

    $ 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

    Vì vậy, lệnh phức tạp hơn của bạn thực sự sẽ bỏ lỡ hai gói trên máy của tôi, mà tôi muốn loại bỏ (bây giờ có thể những thứ đó linux-image-extra-*phụ thuộc vào vật thể linux-image-*và do đó sẽ bị xóa bằng mọi cách, nhưng nó không thể làm cho nó rõ ràng). Ở mức độ nào, tôi không thấy điểm sắp xếp của bạn; một đơn giản grep -vmà không cần tiền xử lý sẽ tốt, có lẽ thậm chí còn tốt hơn. Tôi là người ủng hộ nguyên tắc KISS. Nó sẽ giúp bạn dễ dàng hiểu hoặc gỡ lỗi sau này. Ngoài ra, không cần sắp xếp, nó hiệu quả hơn một chút;)

  4. Điều này hoàn toàn là vô trùng nhưng bạn sẽ nhận được cùng một đầu ra với biến thể ngắn hơn một chút này. :-)

    $ 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

Do đó, tôi kết thúc bằng lệnh đơn giản và an toàn hơn

$ 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

Vì bạn thực sự muốn dọn sạch /bootphân vùng của mình , nên một cách tiếp cận hoàn toàn khác là liệt kê nội dung /boot, sử dụng dpkg -Sđể xác định các gói mà các tệp riêng lẻ thuộc về, lọc ra các gói thuộc về kernel hiện tại và loại bỏ các gói kết quả. Nhưng tôi thích cách tiếp cận của bạn hơn, bởi vì nó cũng sẽ tìm thấy các gói lỗi thời như linux-headers-*, không được cài đặt /boot, nhưng để /usr/src.


Cảm ơn phản hồi của bạn @Malte, cảm ơn bạn đã đóng góp. Tôi thấy hai bước đầu tiên của bạn rất rõ ràng và chúng làm cho oneliner thực sự an toàn hơn. Tuy nhiên, tôi tin rằng hai bước cuối cùng của bạn bỏ qua các hạt nhân mới hơn và cũng thanh lọc chúng. Ít nhất, tôi đã thử giải pháp của bạn trên một máy chủ của tôi và nó đã gỡ cài đặt thứ gì đó không mong muốn.
Alejandro

Nó thật thú vị. Bạn có thể PM cho tôi hai kết quả đầu ra, một với lệnh có đề xuất thứ ba và thứ tư của tôi, một không có chúng? Cộng với đầu ra của uname -r. Đối với tôi nó hoạt động tốt. Sẽ rất thú vị để xem tại sao nó không hoạt động trong trường hợp của bạn.
Malte Skoruppa

1
Tôi đã cố gắng PM cho bạn nhưng tôi không tìm thấy địa chỉ email nào vì vậy tôi sẽ đăng kết quả đầu ra của mình tại đây: hastebin.com/raleyigowe.vhdl uname -r cho thấy máy chủ của tôi đang sử dụng linux-image-3.8.0-34 đôi khi một máy chủ đã tải xuống một kernel mới hơn nhưng nó chưa được cài đặt. Đó là lý do tại sao tôi đang tìm cách để loại bỏ chỉ những hạt nhân cũ.
Alejandro

Lệnh này đã chọn tệp tiêu đề cho kernel hiện tại của tôi, có vẻ như không mong muốn.
Mark Stosberg

1
@MalteSkoruppa, uname -rsản xuất 4.8.0-36-generic , không loại trừ linux-headers-4.8.0-36khỏi danh sách.
Mark Stosberg

7

Tôi đã viết tập lệnh này để loại bỏ các gói "linux- *" có phiên bản ít hơn phiên bản hiện tại đã khởi động. Tôi nghĩ rằng không cần thiết phải kiểm tra trạng thái gói. Lệnh yêu cầu xác nhận trước khi thanh trừng các gói. Nếu bạn không muốn điều đó, hãy thêm tùy chọn -y vào lệnh 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-))

Tuy nhiên, để có thể để lại số lượng hạt dự phòng có thể định cấu hình, tôi khuyên bạn nên sử dụng linux-purgetập lệnh của mình với --keeptùy chọn. Xem ở đây để biết thêm thông tin về kịch bản.


3

TL; DR: bỏ qua phía dưới.

Nó dài hơn một chút mặc dù. Tôi sẽ chia sẻ nó cho bạn:

  1. dpkg -l linux-{image,headers}-* | awk '/^ii/{print $2}'Đúng như Malte đề nghị. Liệt kê các tập tin kernel có liên quan.
  2. egrep '[0-9]+\.[0-9]+\.[0-9]+' Cũng được đề xuất bởi Malte là cách an toàn hơn để chỉ chọn các tệp kernel bằng cách tìm số phiên bản.
  3. Vì hiện tại chúng tôi có thể liệt kê cả gói hình ảnh và gói tiêu đề, nên việc đặt tên gói có thể khác nhau, vì vậy chúng tôi có cách giải quyết này cần thiết cho việc sắp xếp awk 'BEGIN{FS="-"}; {if ($3 ~ /[0-9]+/) print $3"-"$4,$0; else if ($4 ~ /[0-9]+/) print $4"-"$5,$0}'Kết quả là một cột mới có số phiên bản trước tên gói ban đầu như bên dưới:

    $ 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. Bây giờ chúng tôi phải sắp xếp danh sách để ngăn chặn việc gỡ cài đặt bất kỳ hình ảnh mới hơn so với hình ảnh hiện đang chạy. sort -k1,1 --version-sort -rcho chúng tôi cái này:

    $ 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. Bây giờ loại bỏ các tập tin kernel hiện tại và mới hơn sed -e "1,/$(uname -r | cut -f1,2 -d"-")/d" | grep -v -e `uname -r | cut -f1,2 -d"-"`cho chúng ta điều này:

    $ 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. Bây giờ hãy loại bỏ cột đầu tiên mà chúng tôi đã thêm vào awk '{print $2}'để có được chính xác những gì chúng tôi muốn:

    $ 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. Bây giờ chúng ta có thể cung cấp cho trình quản lý gói để tự động xóa mọi thứ và cấu hình lại grub:

    Tôi khuyên bạn nên thực hiện chạy khô trước (mặc dù với mục đích tạo kịch bản của bạn, điều này có thể không thực tế nếu bạn có môi trường rộng lớn)

    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

    Bây giờ nếu mọi thứ có vẻ tốt hãy tiếp tục và thực sự loại bỏ nó bằng:

    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

Một lần nữa, toàn bộ quan điểm của "một lớp lót" này là chỉ loại bỏ các hạt nhân OLTER so với hạt nhân hiện đang chạy (để lại bất kỳ hạt nhân mới được cài đặt nào vẫn có sẵn)

Cảm ơn cho tôi biết làm thế nào điều này làm việc cho bạn và nếu bạn có thể cải thiện nó!


Kiểm tra câu trả lời
jarno

1

Bạn có thể chỉ cần liệt kê thư mục / boot để xem các phiên bản kernel mà bạn đang sử dụng lệnh 'ls'. Sau đó, sử dụng 'sudo apt-get -y purge "xxx"' trong đó "xxx" được thay thế bằng số phiên bản bạn muốn xóa. Hãy cẩn thận rằng đó không phải là phiên bản bạn hiện đang chạy !!.


1
Họ muốn một lệnh một lót. Giải pháp của bạn cần nhiều hơn 1 dòng
Anwar


0

Trả lời nhanh, giải thích theo yêu cầu:

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
Tôi đề nghị (hoặc, nếu bạn thích, yêu cầu) mở rộng điều này để bao gồm phần giải thích. :)
Eliah Kagan

@EliahKagan, tôi nghĩ kịch bản không có ý nghĩa. Tại sao bỏ qua các gói không mong muốn được cài đặt? Kịch bản có thể loại bỏ một số hạt nhân mới hơn so với mã hiện tại hoặc lưu một số hạt cũ hơn bằng sed '$d'lệnh. Kịch bản không xóa bất kỳ gói tiêu đề linux hoặc các gói khác liên quan đến các gói kernel cần xóa, ngoài ra nó không xóa các tệp cấu hình của các gói. Tôi sẽ khuyên bạn nên sử dụng câu trả lời của tôi, thay vào đó.
jarno

@EliahKagan Thực tế tập lệnh không xóa bất kỳ gói nào, nhưng in (bằng echo) apt-getlệnh mà bạn có thể chạy.
jarno

0

Tôi thực sự mệt mỏi với tất cả sự phức tạp không cần thiết này và đã tạo ra một gói Python khiến cho một lớp lót trở nên tầm thường:

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

Cài đặt nó với

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

Xem thêm tại https://github.com/mrts/ubfox-old-kernel-cleanup .

Hy vọng điều này sẽ giúp những người khác quá.


Đã thử điều này nhưng tôi gặp lỗi: "ubfox-old-kernel-cleanup: không tìm thấy lệnh"
Cấp

Sau đó, nó không nằm trong đường dẫn tìm kiếm thực thi của bạn. Bạn đã cài đặt nó sudo pip install ...như mô tả ở trên? sudolà thực sự quan trọng, nếu không pipsẽ cài đặt nó trong một số thư mục người dùng và shell có thể không tìm kiếm thư mục này cho các tập tin thực thi.
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

Hoạt động mọi lúc, và thậm chí cả Ubuntu 17.10


Đối với tôi điều này cố gắng để loại bỏ linux-libc-dev:amd64, đó là không mong muốn.
Malte Skoruppa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.