debian 12 硬盘管理脚本 - 秋兮

debian 12 硬盘管理脚本

(一).检测主机上所有非系统盘信息

(二).显示以分区或者未分区的硬盘信息并显示挂载目录

(1).可以对未分区的硬盘进行分区并格式化

(2).初始化以分区的硬盘,恢复未格式化状态

(3).把以分区格式化的分区挂载到系统路径,并实现开机自动挂载。(互交模式,用户需要指定挂载路径)

(4).卸载以挂载的分区

cat > /root/disk_manager.sh << 'EOF'
#!/bin/bash

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # 恢复默认颜色

# 检查root权限
if [ "$(id -u)" -ne 0 ]; then
    echo -e "${RED}错误:此脚本必须以root权限运行!${NC}" >&2
    exit 1
fi

# 安装必要工具
apt-get update && apt-get install -y util-linux parted e2fsprogs

# 获取系统盘
get_sys_disk() {
    local root_device=$(findmnt -n -o SOURCE /)
    local sys_disk=$(lsblk -no pkname "$root_device" 2>/dev/null | head -1)
    [[ -z "$sys_disk" ]] && sys_disk=$(lsblk -ndo name,mountpoint | awk '$2=="/" {print $1}' | sed 's/[0-9]*$//')
    [[ -z "$sys_disk" ]] && sys_disk="sda"
    echo "$sys_disk"
}

# 检测所有非系统硬盘
detect_disks() {
    local sys_disk=$(get_sys_disk)
    declare -gA DISK_INFO
    declare -ga DISK_LIST
    
    # 清空数组
    DISK_LIST=()
    DISK_INFO=()
    
    while IFS= read -r disk; do
        local disk_name=$(basename "$disk")
        [[ "$disk_name" == *"$sys_disk"* ]] && continue
        [[ "$disk" =~ ^/dev/(sd|vd|nvme)[a-z0-9]+$ ]] || continue
        
        # 获取磁盘信息
        local size=$(lsblk -dnbo SIZE "$disk" | awk '{printf "%.1f GB", $1/1024/1024/1024}')
        local partitions=$(lsblk -lno NAME,TYPE,MOUNTPOINT,FSTYPE,SIZE "$disk" 2>/dev/null | grep -v "^$disk_name ")
        
        # 存储磁盘信息
        DISK_INFO["$disk"]="size:$size;partitions:$partitions"
        DISK_LIST+=("$disk")
    done < <(lsblk -dpno NAME,TYPE 2>/dev/null | awk '$2=="disk" {print $1}')
    
    return ${#DISK_LIST[@]}
}

# 显示磁盘信息
show_disks() {
    echo -e "${BLUE}=============================================${NC}"
    echo -e "${CYAN}          检测到的非系统硬盘              ${NC}"
    echo -e "${BLUE}=============================================${NC}"
    
    if [ ${#DISK_LIST[@]} -eq 0 ]; then
        echo -e "${YELLOW}未检测到任何非系统硬盘!${NC}"
        return 1
    fi
    
    for i in "${!DISK_LIST[@]}"; do
        local disk="${DISK_LIST[$i]}"
        local info="${DISK_INFO[$disk]}"
        local size=$(echo "$info" | grep -oP 'size:\K[^;]+')
        local partitions=$(echo "$info" | grep -oP 'partitions:\K.*')
        
        echo -e "${GREEN}$((i+1)). ${disk}${NC} - ${YELLOW}$size${NC}"
        
        if [ -z "$partitions" ] || [ "$(echo "$partitions" | wc -l)" -eq 0 ]; then
            echo -e "   ${RED}状态: 未分区${NC}"
        else
            echo -e "   ${MAGENTA}分区信息:${NC}"
            echo "$partitions" | while read -r line; do
                if [ -z "$line" ]; then
                    continue
                fi
                
                local part_name=$(echo "$line" | awk '{print $1}')
                local part_type=$(echo "$line" | awk '{print $2}')
                local part_mount=$(echo "$line" | awk '{print $3}')
                local part_fstype=$(echo "$line" | awk '{print $4}')
                local part_size=$(echo "$line" | awk '{print $5}')
                
                if [ "$part_type" == "part" ]; then
                    if [ -z "$part_mount" ]; then
                        echo -e "     ${CYAN}/dev/$part_name${NC} ($part_size, $part_fstype) - ${YELLOW}未挂载${NC}"
                    else
                        echo -e "     ${CYAN}/dev/$part_name${NC} ($part_size, $part_fstype) - ${GREEN}已挂载到 $part_mount${NC}"
                    fi
                fi
            done
        fi
        echo ""
    done
    return 0
}

# 分区并格式化硬盘
partition_disk() {
    local disk="$1"
    echo -e "${YELLOW}正在处理磁盘: $disk${NC}"
    
    # 检查是否已有分区
    if lsblk "$disk" | grep -q 'part'; then
        echo -e "${RED}错误:磁盘已有分区!请先删除分区。${NC}"
        return 1
    fi
    
    # 创建分区表
    echo -e "${BLUE}创建GPT分区表...${NC}"
    parted -s "$disk" mklabel gpt >/dev/null 2>&1
    
    # 创建分区
    echo -e "${BLUE}创建主分区...${NC}"
    parted -s "$disk" mkpart primary 0% 100% >/dev/null 2>&1
    
    # 获取分区名称
    local partition
    if [[ "$disk" =~ /dev/nvme ]]; then
        partition="${disk}p1"
    else
        partition="${disk}1"
    fi
    
    # 等待分区出现
    sleep 2
    if [ ! -e "$partition" ]; then
        # 尝试刷新分区表
        partprobe "$disk"
        sleep 1
        if [ ! -e "$partition" ]; then
            echo -e "${RED}错误:分区创建失败!${NC}"
            return 1
        fi
    fi
    
    # 格式化分区
    echo -e "${BLUE}格式化为ext4文件系统...${NC}"
    mkfs.ext4 -F "$partition" >/dev/null 2>&1
    
    echo -e "${GREEN}磁盘 $disk 分区和格式化完成!${NC}"
    return 0
}

# 删除分区
delete_partitions() {
    local disk="$1"
    echo -e "${YELLOW}正在删除磁盘 $disk 的所有分区...${NC}"
    
    # 获取所有分区
    local partitions=$(lsblk -lno NAME,TYPE "$disk" | awk '$2=="part" {print "/dev/"$1}')
    
    if [ -z "$partitions" ]; then
        echo -e "${YELLOW}磁盘没有分区,无需删除。${NC}"
        return 0
    fi
    
    # 卸载所有分区
    for part in $partitions; do
        if findmnt "$part" >/dev/null; then
            echo -e "${BLUE}卸载分区 $part...${NC}"
            umount "$part" 2>/dev/null
        fi
        
        # 从fstab中移除
        local uuid=$(blkid -s UUID -o value "$part" 2>/dev/null)
        if [ -n "$uuid" ]; then
            sed -i "\|^UUID=$uuid|d" /etc/fstab
        fi
    done
    
    # 删除分区
    echo -e "${BLUE}删除分区表...${NC}"
    parted -s "$disk" mklabel gpt >/dev/null 2>&1
    
    echo -e "${GREEN}磁盘 $disk 的所有分区已删除!${NC}"
    return 0
}

# 挂载分区
mount_partition() {
    local disk="$1"
    local partition
    
    if [[ "$disk" =~ /dev/nvme ]]; then
        partition="${disk}p1"
    else
        partition="${disk}1"
    fi
    
    # 检查分区是否存在
    if [ ! -e "$partition" ]; then
        echo -e "${RED}错误:分区 $partition 不存在!${NC}"
        return 1
    fi
    
    # 获取UUID
    local uuid=$(blkid -s UUID -o value "$partition" 2>/dev/null)
    if [ -z "$uuid" ]; then
        echo -e "${RED}错误:无法获取分区UUID!${NC}"
        return 1
    fi
    
    # 检查是否已挂载
    if findmnt "$partition" >/dev/null; then
        local current_mount=$(findmnt -n -o TARGET "$partition")
        echo -e "${YELLOW}分区已挂载到 $current_mount${NC}"
        read -rp "是否重新挂载到其他位置? (y/n): " choice
        if [[ ! "$choice" =~ ^[Yy]$ ]]; then
            return 0
        fi
        umount "$partition" 2>/dev/null
    fi
    
    # 获取挂载点
    while true; do
        read -rp "请输入挂载点路径 (例如 /mnt/data): " mount_point
        
        if [[ ! "$mount_point" =~ ^/[a-zA-Z0-9/_-]+$ ]]; then
            echo -e "${RED}错误:无效路径!必须是绝对路径。${NC}"
            continue
        fi
        
        if [ -d "$mount_point" ]; then
            if [ -n "$(ls -A "$mount_point")" ]; then
                echo -e "${YELLOW}警告:目录非空!挂载后原有内容将被隐藏。${NC}"
                read -rp "确认使用此目录? (y/n): " confirm
                [[ "$confirm" =~ ^[Yy]$ ]] && break
            else
                break
            fi
        else
            mkdir -p "$mount_point" && break
        fi
    done
    
    # 挂载分区
    if mount "$partition" "$mount_point"; then
        echo -e "${GREEN}分区已挂载到 $mount_point${NC}"
        
        # 添加到fstab
        if ! grep -q "UUID=$uuid" /etc/fstab; then
            echo "UUID=$uuid $mount_point ext4 defaults 0 2" >> /etc/fstab
            echo -e "${GREEN}已添加到 /etc/fstab${NC}"
        else
            echo -e "${YELLOW}设备已在fstab中注册${NC}"
        fi
    else
        echo -e "${RED}挂载失败!${NC}"
        return 1
    fi
    
    return 0
}

# 卸载分区
unmount_partition() {
    local disk="$1"
    local partition
    
    if [[ "$disk" =~ /dev/nvme ]]; then
        partition="${disk}p1"
    else
        partition="${disk}1"
    fi
    
    # 检查分区是否存在
    if [ ! -e "$partition" ]; then
        echo -e "${RED}错误:分区 $partition 不存在!${NC}"
        return 1
    fi
    
    # 检查是否已挂载
    if ! findmnt "$partition" >/dev/null; then
        echo -e "${YELLOW}分区未挂载${NC}"
        return 0
    fi
    
    # 获取挂载点
    local mount_point=$(findmnt -n -o TARGET "$partition")
    echo -e "${YELLOW}正在卸载 $partition (挂载于 $mount_point)${NC}"
    
    # 卸载分区
    if umount "$partition"; then
        echo -e "${GREEN}分区已卸载${NC}"
        
        # 从fstab中移除
        local uuid=$(blkid -s UUID -o value "$partition" 2>/dev/null)
        if [ -n "$uuid" ]; then
            sed -i "\|^UUID=$uuid|d" /etc/fstab
            echo -e "${GREEN}已从 /etc/fstab 移除${NC}"
        fi
        
        # 询问是否删除目录
        read -rp "是否删除挂载点目录 $mount_point? (y/n): " choice
        if [[ "$choice" =~ ^[Yy]$ ]]; then
            rmdir "$mount_point" 2>/dev/null
            echo -e "${GREEN}目录已删除${NC}"
        fi
    else
        echo -e "${RED}卸载失败!可能有进程正在使用。${NC}"
        return 1
    fi
    
    return 0
}

# 主菜单
main_menu() {
    while true; do
        # 每次循环都重新检测磁盘状态
        detect_disks
        
        clear
        echo -e "${BLUE}=============================================${NC}"
        echo -e "${CYAN}          Debian 12 硬盘管理工具            ${NC}"
        echo -e "${BLUE}=============================================${NC}"
        show_disks
        
        if [ ${#DISK_LIST[@]} -eq 0 ]; then
            echo -e "${YELLOW}没有可操作的硬盘!${NC}"
            read -rp "按Enter键返回..." dummy
            continue
        fi
        
        echo -e "${MAGENTA}请选择操作:${NC}"
        echo -e "  ${GREEN}1${NC}) 分区并格式化硬盘"
        echo -e "  ${GREEN}2${NC}) 删除硬盘所有分区"
        echo -e "  ${GREEN}3${NC}) 挂载分区"
        echo -e "  ${GREEN}4${NC}) 卸载分区"
        echo -e "  ${GREEN}0${NC}) 退出"
        echo ""
        read -rp "请输入选项 [0-4]: " choice
        
        case $choice in
            1) 
                echo -e "${YELLOW}请选择要分区的硬盘:${NC}"
                select_disk "unpartitioned"
                if [ -n "$selected_disk" ]; then
                    partition_disk "$selected_disk"
                fi
                ;;
            2) 
                echo -e "${YELLOW}请选择要删除分区的硬盘:${NC}"
                select_disk "any"
                if [ -n "$selected_disk" ]; then
                    delete_partitions "$selected_disk"
                fi
                ;;
            3) 
                echo -e "${YELLOW}请选择要挂载的硬盘:${NC}"
                select_disk "partitioned"
                if [ -n "$selected_disk" ]; then
                    mount_partition "$selected_disk"
                fi
                ;;
            4) 
                echo -e "${YELLOW}请选择要卸载的硬盘:${NC}"
                select_disk "mounted"
                if [ -n "$selected_disk" ]; then
                    unmount_partition "$selected_disk"
                fi
                ;;
            0) 
                echo -e "${GREEN}退出程序...${NC}"
                exit 0
                ;;
            *) 
                echo -e "${RED}无效选项!${NC}"
                ;;
        esac
        
        read -rp "按Enter键继续..." dummy
    done
}

# 选择硬盘
select_disk() {
    local filter="$1"
    local options=()
    
    for i in "${!DISK_LIST[@]}"; do
        local disk="${DISK_LIST[$i]}"
        local info="${DISK_INFO[$disk]}"
        local partitions=$(echo "$info" | grep -oP 'partitions:\K.*')
        
        case "$filter" in
            "unpartitioned")
                if [ -z "$partitions" ] || [ "$(echo "$partitions" | wc -l)" -eq 0 ]; then
                    options+=("$disk")
                fi
                ;;
            "partitioned")
                if [ -n "$partitions" ] && [ "$(echo "$partitions" | grep -c 'part')" -gt 0 ]; then
                    options+=("$disk")
                fi
                ;;
            "mounted")
                if echo "$partitions" | grep -q 'part.*/' ; then
                    options+=("$disk")
                fi
                ;;
            "any")
                options+=("$disk")
                ;;
        esac
    done
    
    if [ ${#options[@]} -eq 0 ]; then
        echo -e "${YELLOW}没有符合条件的硬盘!${NC}"
        selected_disk=""
        return 1
    fi
    
    echo -e "${CYAN}可用的硬盘:${NC}"
    for i in "${!options[@]}"; do
        echo -e "  ${GREEN}$((i+1))${NC}) ${options[$i]}"
    done
    echo -e "  ${GREEN}0${NC}) 取消"
    
    while true; do
        read -rp "请选择硬盘 [0-${#options[@]}]: " selection
        
        if [[ "$selection" == "0" ]]; then
            selected_disk=""
            break
        elif [[ "$selection" =~ ^[0-9]+$ ]] && [ "$selection" -ge 1 ] && [ "$selection" -le ${#options[@]} ]; then
            selected_disk="${options[$((selection-1))]}"
            break
        else
            echo -e "${RED}无效选择!请输入 0 到 ${#options[@]} 之间的数字${NC}"
        fi
    done
    
    return 0
}

# 主程序
detect_disks
main_menu
EOF


进入/root目录

cd /root


添加执行权限:

chmod +x disk_manager.sh


以root运行:

sudo ./disk_manager.sh