sh 根据脚本中定义的规则清除冗余的Ubuntu内核文件,例如要保留的内核数量

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sh 根据脚本中定义的规则清除冗余的Ubuntu内核文件,例如要保留的内核数量相关的知识,希望对你有一定的参考价值。

#!/bin/bash

# What if we could adjust the clock, 
#     making a day of a virtual AI world much shorter than ours?
# What if a virtual AI being could spend its whole long life 
#     in a blink of our eyes?

#############################################################
# Purpose: 
# Purge redundant Ubuntu kernel files by rules defined in the script
#     such as the number of kernels to be preserved

# Compatibility:
# Ubuntu 16, 18; Debian 8, 9 amd64
# And probably some other debian distributions

# Usage: 
# 1. Default mode, purge the redundant
#     /path/to/purge_kernel_by_rules.bash
# 2. Manual arguments mode, selectively purge. 
#     It's also affected by default values *KERNELS_TO_PRESERVE.
# 2.1 One argument, no need for other kernel packages such as linux-header-
#     /path/to/purge_kernel_by_rules.bash linux-image-333.16.0-6-amd64
#     /path/to/purge_kernel_by_rules.bash "linux-image-333.16.0-6-amd64"
# 2.2 Multiple arguments
#     ./purge_kernel_by_rules.bash linux-image-333.16.0-6-amd64 linux-image-444.4.0-28-generic
#     ./purge_kernel_by_rules.bash "linux-image-444.16.0-20-generic linux-image-444.16.0-20-generic"
# 3. Pipe mode
# 3.1 Simple pipe
#     echo linux-image-333.16.0-6-amd64 linux-image-444.4.0-28-generic | ./purge_kernel_by_rules.bash
# 3.2 Pipe mixed with arguments input
#     echo linux-image-333.16.0-6-amd64 | ./purge_kernel_by_rules.bash linux-image-444.4.0-28-generic
#     The arguments input are listed and purged before the pipe.

# You can also change the number of oldest kernels or newest kernels  
#     that you'd like to preserve 
#     by adjusting the values of NUMBER_OF_OLDEST_KERNELS_TO_PRESERVE
#     and NUMBER_OF_NEWEST_KERNELS_TO_PRESERVE
# By default 1 oldest and 2 newest along with the ruuning kernel
#    are reserved when purge the kernels

# For the running kernel version:
#     If it's in the range of oldest/newest kernels
#         then the final reserve list will be generated by
#         user-defined defalut values
#     If it's not in the range of oldest/newest kernels
#         then the final reserve list will be generated by
#         (user-defined defalut values + running kernel version)

# The number of remaining kernels after purge 
#    shouldn't be less than the number of total kernels to preserve

#### WARNINGS: 
#### This script could seriously damage your system or computer
####    if you use it improperly or carelessly
#### So, use it with cautions and at your own risks
#### A test environment is preferred 

# ATTENTION: 
# You'd have at least 1 kernel 
#     for your system to run

# If the numbers here are all 0
#     then only the running kernel is reserved
#     and all the rest kernels are purged
SET_DEFAULT_VALUES_FOR_RESERVATION(){
    NUMBER_OF_OLDEST_KERNELS_TO_PRESERVE=1
    NUMBER_OF_NEWEST_KERNELS_TO_PRESERVE=2
    number_of_kernels_to_preserve=$((NUMBER_OF_OLDEST_KERNELS_TO_PRESERVE + NUMBER_OF_NEWEST_KERNELS_TO_PRESERVE))
}

print_with_tail_newline(){
    printf "$1 \n\n"
}

notice_to_check(){
    echo
    echo "NOTICE: Check your default values and reset them properly."
    print_with_tail_newline "NOTICE: No removing kernels. Exit." 
}

check_minimum_values_for_reservation(){
    if [ 0 -ge $number_of_kernels_to_preserve ]
        then
        echo
        echo "** CAUTION: The number of non-running kernels to preserve is 0. "
    fi
}

handle_default_values_for_reservation(){
    SET_DEFAULT_VALUES_FOR_RESERVATION    
}

get_running_kernel_info(){
    sys_running=`uname -s`
    ver_running=`uname -r`
    # ver_running="4.4.0-134"
}

list_kernel_candidates(){
    print_with_tail_newline "NOTICE: Existing candidate kernel packages on your system:"
    dpkg -l | grep ' linux-\(image\|headers\|image-extra\|signed-image\|modules\|modules-extra\)'
    print_with_tail_newline "========================================"
    
    issue_info=$(cat /etc/issue)
    echo "Currently running:"
    echo "    $issue_info"
    echo "$(echo '    '$sys_running $ver_running)" 
}

get_script_args(){
    str_list_arg_input_LINUX_IMAGE="$@"
}

generate_OS_LINUX_IMAGE_list(){
    # all the linux-image-[ver] pkges on your system
    str_list_OS_LINUX_IMAGE=$(dpkg --list | grep linux-image-[0-9] | awk '{ print $2 }' | sort -V | xargs echo)
    
    arr_list_OS_LINUX_IMAGE=($str_list_OS_LINUX_IMAGE)   
    length_of_arr_list_OS_LINUX_IMAGE=${#arr_list_OS_LINUX_IMAGE[@]}
    #print_with_tail_newline $length_of_arr_list_OS_LINUX_IMAGE
    #print_with_tail_newline ${arr_list_OS_LINUX_IMAGE[0]}
}

check_OS_LINUX_IMAGE_list_length(){
    if [ $length_of_arr_list_OS_LINUX_IMAGE -le $number_of_kernels_to_preserve ] 
        then
        echo "NOTICE: The number of found linux-image kernel versions"
        echo "NOTICE:     were less or equal to $number_of_kernels_to_preserve ."
        notice_to_check
        exit 1
    fi
}

check_empty_space_input(){
    # invalid input like "    "    
    str=$(echo $str_input_list_LINUX_IMAGE)   
    if [ "y" == "y$str" ]
        then
        print_with_tail_newline "NOTICE: Invalid empty input::Empty kernel string. Exit."
        exit 1
    fi
}

check_OS_LINUX_IMAGE_list_length_for_input(){    
    INPUT_LINUX_IMAGE_list_arr=($str_input_list_LINUX_IMAGE)
    INPUT_LINUX_IMAGE_list_arr_length=${#INPUT_LINUX_IMAGE_list_arr[@]}

    number_of_kernels_to_remain=$((length_of_arr_list_OS_LINUX_IMAGE - INPUT_LINUX_IMAGE_list_arr_length))
    
    if [ $number_of_kernels_to_preserve -gt $number_of_kernels_to_remain ] 
        then        
        echo "NOTICE: The number of remaining versions of linux-image kernel"
        echo "NOTICE:     should be GREATER than $number_of_kernels_to_preserve"
        echo "NOTICE:     after purging the input."
        notice_to_check
        exit 1
    fi   
}

get_running_image_str(){
    for image_str in ${arr_list_OS_LINUX_IMAGE[@]}
        do
        result=$(printf "$image_str" | grep -n "$ver_running")
        if [ 0 -eq $? ]
            then
            # remove the leading "num:" part in the result
            image_str_running="${result#*:}"
            break
        fi
    done

    #echo "arr_list_OS_LINUX_IMAGE: ${arr_list_OS_LINUX_IMAGE[@]}"
    #echo "image_str_running: $image_str_running" 
}

make_raw_reserve_list(){
    # make list for the oldest kernels to reserve
    arr_reserve_list_oldest_LINUX_IMAGE=(${arr_list_OS_LINUX_IMAGE[@]:0:$NUMBER_OF_OLDEST_KERNELS_TO_PRESERVE})
    str_reserve_list_oldest_LINUX_IMAGE="${arr_reserve_list_oldest_LINUX_IMAGE[@]}"

    # make list for the newest kernels to reserve
    length=${#arr_list_OS_LINUX_IMAGE[@]}
    start_idx_arr_reserve_list_newest_LINUX_IMAGE=$(($length - $NUMBER_OF_NEWEST_KERNELS_TO_PRESERVE))
    arr_reserve_list_newest_LINUX_IMAGE=(${arr_list_OS_LINUX_IMAGE[@]:$start_idx_arr_reserve_list_newest_LINUX_IMAGE})
    str_reserve_list_newest_LINUX_IMAGE="${arr_reserve_list_newest_LINUX_IMAGE[@]}"
    
    reserve_list_raw="$str_reserve_list_oldest_LINUX_IMAGE $str_reserve_list_newest_LINUX_IMAGE"
}

make_reserve_list(){
    # add the running kernel version to the raw_reserve_list #

    check_minimum_values_for_reservation
    get_running_image_str
    make_raw_reserve_list

    printf "$reserve_list_raw" | grep -q "$image_str_running"
    if [ 0 -ne $? ] 
        then
        reserve_list="$image_str_running $reserve_list_raw"
    else
        reserve_list="$reserve_list_raw"
    fi
    
    print_with_tail_newline "Reserved kernel list: $reserve_list" 
}

do_input(){
    # arg input, pipe input or pipe with arg input
    str_input_list_LINUX_IMAGE=$1
    
    check_empty_space_input
    check_OS_LINUX_IMAGE_list_length_for_input
    arr_raw_purge_list_LINUX_IMAGE=($str_input_list_LINUX_IMAGE)
    
    make_reserve_list
}

make_reserve_list_for_default(){
    # only show reserve list for terminal users
    # not really used by the default mode
    make_reserve_list
    
    # This is the real reserve_list used by the default mode
    get_running_image_str
    reserve_list="$image_str_running"
}

do_default(){
    echo "NOTICE: Purge with default mode."

    kernel_purge_list_length=$(($length_of_arr_list_OS_LINUX_IMAGE - $number_of_kernels_to_preserve))
    arr_raw_purge_list_LINUX_IMAGE=(${arr_list_OS_LINUX_IMAGE[@]:$NUMBER_OF_OLDEST_KERNELS_TO_PRESERVE:$kernel_purge_list_length})
    arr_raw_purge_list_LINUX_IMAGE_length=${#arr_raw_purge_list_LINUX_IMAGE[@]}
    
    make_reserve_list_for_default
}

do_nopipe(){
    # manual argument mode, purge from user arguments input
    if [ -n "$str_list_arg_input_LINUX_IMAGE" ]
        then
        echo "NOTICE: Purge with user arguments input mode."
        do_input "$str_list_arg_input_LINUX_IMAGE"
    fi
    
    # default mode, no user-input arg
    if [ -z "$str_list_arg_input_LINUX_IMAGE" ]
        then
        do_default
    fi
}

do_pipe(){
    echo "NOTICE: Purge with user pipe (or pipe-mixed) input mode."

    # cat from default stdin, which receive data from the pipe
    str_pipe_lines_LINUX_IMAGE=$(cat | tr -s '\n' ' ')    
    str_list_pipe_input_LINUX_IMAGE="$str_list_arg_input_LINUX_IMAGE $str_pipe_lines_LINUX_IMAGE"
    do_input "$str_list_pipe_input_LINUX_IMAGE"
}

how_to_do(){
    generate_OS_LINUX_IMAGE_list
    check_OS_LINUX_IMAGE_list_length
    
    # check pipe status
    if [ -t 0 ]
        then
        do_nopipe
    else
        do_pipe
    fi
}

init_purge_list_strs(){
    # 1 package for ubuntu and debian 8 amd64
    str_purge_list_LINUX_IMAGE=""
    
    # 3 packages for ubuntu 16
    str_purge_list_LINUX_HEADERS=""
    str_purge_list_LINUX_IMAGE_EXTRA=""
    str_purge_list_LINUX_SIGNED_IMAGE=""
    
    # 2 packages for ubuntu 18
    str_purge_list_LINUX_MODULES=""
    str_purge_list_LINUX_MODULES_EXTRA=""
    
    # all packages for both ubuntu and debian 
    kernel_purge_list_str=""
}

get_version_numbers_by_image_string(){
    image_ver=$(echo $image_string | cut -d - -f 3-4)
    ver_n1=${image_ver%%.*}
    ver_n1_n2=${image_ver%.*}
    ver_n2=${ver_n1_n2#*.}
}

get_ubuntu_unique_kernels(){
    # change header kernel format from debian to ubuntu
    arr_purge_list_LINUX_HEADERS[$j]=${debian_header//-common}

    get_version_numbers_by_image_string         
    # ubuntu 18, kernel 4.15.0
    if [[ ("$ver_n1" -eq 4 && "$ver_n2" -ge 15) || "$ver_n1" -ge 5 ]]
        then
        arr_purge_list_LINUX_MODULES[$j]="${image_string/image/modules}"
        arr_purge_list_LINUX_MODULES_EXTRA[$j]="${image_string/image/modules-extra}"
    else
        arr_purge_list_LINUX_IMAGE_EXTRA[$j]="${image_string//image/image-extra}"
        arr_purge_list_LINUX_SIGNED_IMAGE[$j]="${image_string//image/signed-image}"
    fi
}

get_linux_distribution_unique_kernels(){
    provider_id=${issue_info%% *}
    #for test
    #provider_id="Debian"

    length=${#arr_raw_purge_list_LINUX_IMAGE[@]}
    j=0
    for ((i=0;$i<$length;i++))
        do
        # skip if the kernel string is in the reserved kernel version list
        image_string="${arr_raw_purge_list_LINUX_IMAGE[$i]}"
 
        printf "$reserve_list" | grep -q "$image_string"
        if [ 0 -eq $? ] 
            then
            continue
        fi
        
        #echo "j: $j"
        # header for debian
        debian_header="${image_string//image/headers}"
        arr_purge_list_LINUX_HEADERS[$j]="$debian_header"
        
        # image for debian, ubuntu
        arr_purge_list_LINUX_IMAGE[$j]="$image_string"
        
        # ubuntu 16, 18
        if [ "Ubuntu" == "$provider_id" ]
            then
            get_ubuntu_unique_kernels  
        fi
        j=$((j+1))
    done   
}

format_str_kernel_purge_list(){
    # change *_purge_list arr to str here
    kernel_purge_list_str=" \
        $str_purge_list_LINUX_IMAGE \
        $str_purge_list_LINUX_HEADERS \
        $str_purge_list_LINUX_IMAGE_EXTRA \
        $str_purge_list_LINUX_SIGNED_IMAGE \
        $str_purge_list_LINUX_MODULES \
        $str_purge_list_LINUX_MODULES_EXTRA"
}

print_if_no_empty_line(){
    str_purge_list_no_side_spaces="$(echo $1)"
        if [ y"" != y"$str_purge_list_no_side_spaces" ]
            then 
            echo "$str_purge_list_no_side_spaces"
        fi
}

print_kernel_purge_list(){
    print_if_no_empty_line "$str_purge_list_LINUX_IMAGE" 
    print_if_no_empty_line "$str_purge_list_LINUX_HEADERS"
    echo

    print_if_no_empty_line "$str_purge_list_LINUX_IMAGE_EXTRA"
    print_if_no_empty_line "$str_purge_list_LINUX_SIGNED_IMAGE"
    echo

    print_if_no_empty_line "$str_purge_list_LINUX_MODULES"
    print_if_no_empty_line "$str_purge_list_LINUX_MODULES_EXTRA"
    echo
}

generate_kernel_purge_list_str(){
    print_with_tail_newline "NOTICE: Generated lists of all kernel packages to be purged:"
    init_purge_list_strs   
    get_linux_distribution_unique_kernels       

    str_purge_list_LINUX_HEADERS="${arr_purge_list_LINUX_HEADERS[@]}"
    str_purge_list_LINUX_IMAGE="${arr_purge_list_LINUX_IMAGE[@]}"
    str_purge_list_LINUX_IMAGE_EXTRA="${arr_purge_list_LINUX_IMAGE_EXTRA[@]}"
    str_purge_list_LINUX_SIGNED_IMAGE="${arr_purge_list_LINUX_SIGNED_IMAGE[@]}"
    str_purge_list_LINUX_MODULES="${arr_purge_list_LINUX_MODULES[@]}"
    str_purge_list_LINUX_MODULES_EXTRA="${arr_purge_list_LINUX_MODULES_EXTRA[@]}"    
    print_kernel_purge_list
    format_str_kernel_purge_list
}

vital_check(){
    while true
        do
        echo "NOTICE: Check all the kernel versions above before the next step."
        read -p "Press Ctrl+C to interrupt or press Enter to continue: " input
        if [ -z "$input" ]
            then
            break
        fi
    done

    print_with_tail_newline "Continued.. "
}

purge_kernels_by_purge_list_str(){
    purge_cmd="apt-get purge $kernel_purge_list_str"
    print_with_tail_newline "$purge_cmd"
    
    # grep command in this script could return err
    # so set this in the later part of the script
    set -e
    
    $purge_cmd
    update-grub2
}

main(){
    handle_default_values_for_reservation
    get_running_kernel_info
    list_kernel_candidates

    get_script_args "$@"
    how_to_do
    generate_kernel_purge_list_str

    vital_check
    purge_kernels_by_purge_list_str
}

##################################
main "$@"

以上是关于sh 根据脚本中定义的规则清除冗余的Ubuntu内核文件,例如要保留的内核数量的主要内容,如果未能解决你的问题,请参考以下文章

在ubuntu的终端中运行脚本文件的问题

sh Bash | ubuntu的自定义配置脚本

iOS项目冗余资源扫描脚本

sh 如何在Ubuntu Linux中清除Shell历史记录

sh 清除交换ubuntu

shell脚本的规则