ubuntu多块硬盘挂载到同一目录LVM方式

挂载脚本 lvm_mount.sh

根据用户选择挂载目录以及挂载硬盘

复制代码
#!/bin/bash

# LVM 自动挂载脚本(包含完整 LVM 安装)
set -e

echo "=== LVM 多磁盘挂载脚本 ==="
echo ""

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 函数:检查并安装 LVM
install_lvm() {
    echo -e "${YELLOW}检查 LVM 安装...${NC}"
    
    # 检查必要的 LVM 命令
    local lvm_commands=("pvcreate" "vgcreate" "lvcreate" "lvs" "vgs" "pvs")
    local missing_commands=()
    
    for cmd in "${lvm_commands[@]}"; do
        if ! command -v "$cmd" &> /dev/null; then
            missing_commands+=("$cmd")
        fi
    done
    
    if [ ${#missing_commands[@]} -eq 0 ]; then
        echo -e "${GREEN}✓ LVM 已安装${NC}"
        return 0
    fi
    
    echo -e "${YELLOW}安装 LVM2 包...${NC}"
    
    # 更新包列表
    if ! apt update; then
        echo -e "${RED}错误: 无法更新包列表${NC}"
        return 1
    fi
    
    # 安装 LVM2
    if apt install -y lvm2; then
        echo -e "${GREEN}✓ LVM2 安装成功${NC}"
        
        # 检查并加载内核模块
        echo -e "${YELLOW}检查内核模块...${NC}"
        local modules=("dm_mod" "dm_thin_pool")
        for module in "${modules[@]}"; do
            if ! lsmod | grep -q "$module"; then
                if modprobe "$module"; then
                    echo -e "${GREEN}✓ 加载内核模块: $module${NC}"
                else
                    echo -e "${YELLOW}⚠ 无法加载模块: $module${NC}"
                fi
            fi
        done
        
        # 启动 LVM 服务
        systemctl enable --now lvm2-lvmetad.service &>/dev/null
        systemctl enable --now lvm2-lvmpolld.service &>/dev/null
        
        return 0
    else
        echo -e "${RED}错误: LVM2 安装失败${NC}"
        return 1
    fi
}

# 函数:检查 root 权限
check_root() {
    if [ "$EUID" -ne 0 ]; then
        echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}"
        echo "使用方法: sudo $0"
        exit 1
    fi
}

# 函数:显示磁盘信息
show_disk_info() {
    echo -e "${GREEN}=== 当前系统磁盘信息 ===${NC}"
    echo "设备名称    大小      类型  挂载点       文件系统   型号"
    echo "------------------------------------------------------------"
    lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE,MODEL | grep -v loop
    echo ""
}

# 函数:获取可用磁盘
get_available_disks() {
    echo -e "${YELLOW}扫描可用磁盘...${NC}"
    available_disks=()
    
    # 使用 lsblk 获取磁盘信息
    while IFS= read -r line; do
        if [ -z "$line" ]; then
            continue
        fi
        
        disk_name=$(echo "$line" | awk '{print $1}')
        disk_type=$(echo "$line" | awk '{print $3}')
        mountpoint=$(echo "$line" | awk '{print $4}')
        fstype=$(echo "$line" | awk '{print $5}')
        
        # 检查是否是磁盘类型且未挂载
        if [ "$disk_type" == "disk" ] && [ -z "$mountpoint" ] && [ -z "$fstype" ]; then
            # 进一步检查是否是系统盘(通过检查是否有子分区被挂载为 / )
            if ! lsblk "/dev/$disk_name" | grep -q "/$"; then
                # 检查是否已经有文件系统
                if ! blkid "/dev/$disk_name" &> /dev/null; then
                    available_disks+=("$disk_name")
                    echo -e "${GREEN}  ✓ 找到可用磁盘: /dev/$disk_name${NC}"
                else
                    echo -e "${YELLOW}  ⓘ 跳过 /dev/$disk_name (已有文件系统)${NC}"
                fi
            else
                echo -e "${YELLOW}  ⓘ 跳过 /dev/$disk_name (系统盘)${NC}"
            fi
        fi
    done < <(lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE | tail -n +2)
    
    if [ ${#available_disks[@]} -eq 0 ]; then
        echo -e "${RED}未找到可用的磁盘!${NC}"
        echo "请确认:"
        echo "1. 磁盘已正确插入"
        echo "2. 磁盘未被挂载"
        echo "3. 磁盘没有文件系统"
        return 1
    fi
    
    return 0
}

# 函数:选择磁盘
select_disks() {
    local available_disks=("$@")
    selected_disks=()
    
    echo -e "${GREEN}可用的磁盘:${NC}"
    for i in "${!available_disks[@]}"; do
        disk_info=$(lsblk -b -d -o NAME,SIZE,MODEL "/dev/${available_disks[$i]}" | tail -1)
        disk_size=$(echo "$disk_info" | awk '{print $2}')
        disk_model=$(echo "$disk_info" | awk '{for(i=3;i<=NF;i++) printf $i" "}')
        size_gb=$(echo "scale=2; $disk_size/1024/1024/1024" | bc)
        echo "  $((i+1)). /dev/${available_disks[$i]} (${size_gb} GB) - $disk_model"
    done
    
    echo ""
    echo -e "${YELLOW}请选择要用于 LVM 的磁盘:${NC}"
    echo "输入数字,多个磁盘用空格分隔(例如: 1 2 3)"
    read -r -p "选择: " choices
    
    if [ -z "$choices" ]; then
        echo -e "${RED}错误: 未选择任何磁盘${NC}"
        return 1
    fi
    
    for choice in $choices; do
        index=$((choice-1))
        if [ $index -ge 0 ] && [ $index -lt ${#available_disks[@]} ]; then
            selected_disks+=("/dev/${available_disks[$index]}")
            echo -e "${GREEN}  ✓ 选择: /dev/${available_disks[$index]}${NC}"
        else
            echo -e "${RED}错误: 无效选择 '$choice'${NC}"
            return 1
        fi
    done
    
    if [ ${#selected_disks[@]} -eq 0 ]; then
        echo -e "${RED}错误: 未选择任何磁盘${NC}"
        return 1
    fi
    
    return 0
}

# 函数:输入挂载点
get_mount_point() {
    echo ""
    echo -e "${YELLOW}请输入挂载点目录:${NC}"
    echo "示例:"
    echo "  /home/mnt       # 家目录下的 mnt 文件夹"
    echo "  /data          # 根目录下的 data 文件夹" 
    echo "  /mnt/storage   # 默认的 mnt 目录"
    echo "  /app/data      # 应用数据目录"
    read -r -p "挂载点路径: " mount_point
    
    # 检查输入是否为空
    if [ -z "$mount_point" ]; then
        echo -e "${YELLOW}使用默认挂载点: /mnt/storage${NC}"
        mount_point="/mnt/storage"
    fi
    
    # 移除末尾的斜杠
    mount_point="${mount_point%/}"
    
    # 检查路径是否以斜杠开头
    if [[ ! "$mount_point" =~ ^/ ]]; then
        echo -e "${RED}错误: 挂载点必须是绝对路径(以 / 开头)${NC}"
        return 1
    fi
    
    # 检查目录是否已存在且被挂载
    if mountpoint -q "$mount_point" 2>/dev/null; then
        echo -e "${RED}错误: 目录 $mount_point 已被挂载${NC}"
        return 1
    fi
    
    echo -e "${GREEN}挂载点设置为: $mount_point${NC}"
    return 0
}

# 函数:确认操作
confirm_operation() {
    echo ""
    echo -e "${YELLOW}=== 操作摘要 ===${NC}"
    echo "选择的磁盘: ${selected_disks[*]}"
    echo "卷组名称: $vg_name"
    echo "逻辑卷名称: $lv_name"
    echo "挂载点: $mount_point"
    echo "文件系统: $filesystem"
    echo ""
    echo -e "${RED}警告: 这将格式化所选磁盘,所有数据将被删除!${NC}"
    echo ""
    
    read -r -p "确认执行以上操作?(输入 'YES' 继续): " confirm
    if [ "$confirm" != "YES" ]; then
        echo -e "${YELLOW}操作已取消${NC}"
        exit 0
    fi
}

# 函数:执行 LVM 配置
setup_lvm() {
    local disks=("$@")
    
    echo -e "${GREEN}=== 开始 LVM 配置 ===${NC}"
    
    # 1. 创建物理卷
    echo "步骤 1: 创建物理卷..."
    for disk in "${disks[@]}"; do
        echo -e "  - 处理 $disk"
        if pvcreate "$disk"; then
            echo -e "    ${GREEN}✓ 物理卷创建成功${NC}"
        else
            echo -e "    ${RED}✗ 物理卷创建失败${NC}"
            return 1
        fi
    done
    
    # 2. 创建卷组
    echo "步骤 2: 创建卷组 '$vg_name'..."
    if vgcreate "$vg_name" "${disks[@]}"; then
        echo -e "  ${GREEN}✓ 卷组创建成功${NC}"
    else
        echo -e "  ${RED}✗ 卷组创建失败${NC}"
        return 1
    fi
    
    # 3. 创建逻辑卷
    echo "步骤 3: 创建逻辑卷 '$lv_name'..."
    if lvcreate -n "$lv_name" -l 100%FREE "$vg_name"; then
        echo -e "  ${GREEN}✓ 逻辑卷创建成功${NC}"
    else
        echo -e "  ${RED}✗ 逻辑卷创建失败${NC}"
        return 1
    fi
    
    # 4. 格式化
    echo "步骤 4: 格式化逻辑卷为 $filesystem..."
    lv_path="/dev/$vg_name/$lv_name"
    
    # 检查文件系统工具
    if [ "$filesystem" == "xfs" ] && ! command -v mkfs.xfs &> /dev/null; then
        echo -e "${YELLOW}安装 xfsprogs...${NC}"
        apt install -y xfsprogs
    fi
    
    if [ "$filesystem" == "xfs" ]; then
        mkfs_cmd="mkfs.xfs -f"
    else
        mkfs_cmd="mkfs.ext4"
    fi
    
    if $mkfs_cmd "$lv_path"; then
        echo -e "  ${GREEN}✓ 格式化完成${NC}"
    else
        echo -e "  ${RED}✗ 格式化失败${NC}"
        return 1
    fi
    
    # 5. 创建挂载点
    echo "步骤 5: 创建挂载点..."
    if mkdir -p "$mount_point"; then
        echo -e "  ${GREEN}✓ 挂载点创建成功${NC}"
        
        # 设置合适的权限
        chown root:root "$mount_point"
        chmod 755 "$mount_point"
        echo -e "  ${GREEN}✓ 挂载点权限设置完成${NC}"
    else
        echo -e "  ${RED}✗ 挂载点创建失败${NC}"
        return 1
    fi
    
    # 6. 挂载
    echo "步骤 6: 挂载逻辑卷..."
    if mount "$lv_path" "$mount_point"; then
        echo -e "  ${GREEN}✓ 挂载成功${NC}"
    else
        echo -e "  ${RED}✗ 挂载失败${NC}"
        return 1
    fi
    
    # 7. 设置开机挂载
    echo "步骤 7: 配置开机自动挂载..."
    lv_uuid=$(blkid "$lv_path" -s UUID -o value)
    
    if [ -z "$lv_uuid" ]; then
        echo -e "  ${YELLOW}⚠ 无法获取 UUID,使用设备路径${NC}"
        fstab_entry="/dev/$vg_name/$lv_name $mount_point $filesystem defaults 0 0"
    else
        fstab_entry="UUID=$lv_uuid $mount_point $filesystem defaults 0 0"
    fi
    
    if ! grep -q "$mount_point" /etc/fstab; then
        echo "$fstab_entry" >> /etc/fstab
        echo -e "  ${GREEN}✓ fstab 配置完成${NC}"
    else
        echo -e "  ${YELLOW}⚠ fstab 中已存在该挂载点${NC}"
        # 询问是否替换现有配置
        read -r -p "是否替换现有配置?(y/N): " replace
        if [[ $replace =~ ^[Yy]$ ]]; then
            # 删除现有配置并添加新配置
            sed -i "\|$mount_point|d" /etc/fstab
            echo "$fstab_entry" >> /etc/fstab
            echo -e "  ${GREEN}✓ fstab 配置已更新${NC}"
        fi
    fi
    
    return 0
}

# 主程序
main() {
    # 用户配置
    vg_name="data_vg"
    lv_name="storage_lv"
    filesystem="ext4"
    
    # 检查权限
    check_root
    
    # 安装 LVM
    if ! install_lvm; then
        exit 1
    fi
    
    # 显示当前磁盘信息
    show_disk_info
    
    # 获取可用磁盘
    if ! get_available_disks; then
        exit 1
    fi
    
    # 选择磁盘
    if ! select_disks "${available_disks[@]}"; then
        exit 1
    fi
    
    # 输入挂载点
    if ! get_mount_point; then
        exit 1
    fi
    
    # 确认操作
    confirm_operation
    
    # 执行 LVM 配置
    if setup_lvm "${selected_disks[@]}"; then
        echo ""
        echo -e "${GREEN}=== LVM 配置完成 ===${NC}"
        echo "挂载点: $mount_point"
        echo "总容量: $(df -h $mount_point | awk 'NR==2 {print $2}')"
        echo "可用空间: $(df -h $mount_point | awk 'NR==2 {print $4}')"
        echo ""
        echo -e "${GREEN}验证命令:${NC}"
        echo "df -h $mount_point"
        echo "sudo pvs && sudo vgs && sudo lvs"
    else
        echo -e "${RED}=== LVM 配置失败 ===${NC}"
        exit 1
    fi
}

# 运行主程序
main "$@"

验证脚本 lvm_check.sh

复制代码
#!/bin/bash

echo "=== LVM 完整配置检验 ==="
echo ""

# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 函数:检查命令结果
check_cmd() {
    if $1 >/dev/null 2>&1; then
        echo -e "${GREEN}✓ $2${NC}"
        return 0
    else
        echo -e "${RED}✗ $2${NC}"
        return 1
    fi
}

# 1. 基础挂载检查
echo -e "${BLUE}1. 基础挂载检查${NC}"
if mountpoint -q /home/mnt 2>/dev/null; then
    echo -e "${GREEN}✓ /home/mnt 已正确挂载${NC}"
    df -h /home/mnt | tail -1
else
    echo -e "${RED}✗ /home/mnt 未挂载或挂载异常${NC}"
fi

# 2. LVM 组件检查
echo ""
echo -e "${BLUE}2. LVM 组件检查${NC}"
check_cmd "sudo pvs" "物理卷状态"
sudo pvs 2>/dev/null || true

echo ""
check_cmd "sudo vgs" "卷组状态"  
sudo vgs 2>/dev/null || true

echo ""
check_cmd "sudo lvs" "逻辑卷状态"
sudo lvs 2>/dev/null || true

# 3. 配置检查
echo ""
echo -e "${BLUE}3. 配置检查${NC}"
if grep -q "/home/mnt" /etc/fstab; then
    echo -e "${GREEN}✓ fstab 中找到 /home/mnt 配置${NC}"
    grep "/home/mnt" /etc/fstab
else
    echo -e "${RED}✗ fstab 中未找到 /home/mnt 配置${NC}"
fi

# 4. 功能测试
echo ""
echo -e "${BLUE}4. 功能测试${NC}"
# 写入测试
if sudo touch /home/mnt/test_file 2>/dev/null; then
    echo -e "${GREEN}✓ 写入权限正常${NC}"
    # 删除测试
    if sudo rm /home/mnt/test_file 2>/dev/null; then
        echo -e "${GREEN}✓ 删除权限正常${NC}"
    else
        echo -e "${RED}✗ 删除权限异常${NC}"
    fi
else
    echo -e "${RED}✗ 写入权限异常${NC}"
fi

# 5. 详细信息
echo ""
echo -e "${BLUE}5. 详细信息${NC}"
echo "设备映射:"
ls -la /dev/mapper/ | grep -E "(data_vg|storage_lv)" || echo "  未找到相关设备映射"

echo ""
echo "挂载详情:"
findmnt -n -o SOURCE,TARGET,FSTYPE,SIZE /home/mnt 2>/dev/null || echo "  未找到挂载信息"

# 6. 总结
echo ""
echo -e "${BLUE}6. 检验总结${NC}"
if mountpoint -q /home/mnt 2>/dev/null && \
   sudo lvs >/dev/null 2>&1 && \
   grep -q "/home/mnt" /etc/fstab 2>/dev/null; then
    echo -e "${GREEN}🎉 所有检查通过!LVM 配置完整且正常${NC}"
else
    echo -e "${YELLOW}⚠ 部分检查未通过,请检查上述错误信息${NC}"
fi

卸载脚本,执行选择3,lvm_unmount.sh

复制代码
#!/bin/bash

# LVM 卸载脚本(完全清理版)
set -e

echo "=== LVM 完全卸载脚本 ==="
echo ""

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 检查 root 权限
if [ "$EUID" -ne 0 ]; then
    echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}"
    exit 1
fi

# 函数:强制清理 LVM 缓存和残留
force_clean_lvm_residue() {
    echo -e "${YELLOW}=== 强制清理 LVM 残留 ===${NC}"
    
    # 停止 LVM 相关服务
    echo "停止 LVM 服务..."
    systemctl stop lvm2-lvmetad.service 2>/dev/null || true
    systemctl stop lvm2-lvmpolld.service 2>/dev/null || true
    
    # 清理设备映射器
    echo "清理设备映射器..."
    dmsetup remove_all 2>/dev/null || true
    
    # 重新扫描 LVM
    echo "更新 LVM 缓存..."
    vgscan 2>/dev/null || true
    pvscan 2>/dev/null || true
    
    # 清理 LVM 缓存文件
    echo "清理 LVM 缓存文件..."
    rm -f /etc/lvm/cache/.cache 2>/dev/null || true
    
    # 重新加载设备映射器
    echo "重新加载设备映射器..."
    modprobe -r dm_mod 2>/dev/null || true
    modprobe dm_mod 2>/dev/null || true
    
    # udev 规则更新
    echo "更新 udev 规则..."
    udevadm trigger 2>/dev/null || true
    udevadm settle 2>/dev/null || true
    
    echo -e "${GREEN}✓ 强制清理完成${NC}"
}

# 函数:显示当前 LVM 状态
show_lvm_status() {
    echo -e "${GREEN}=== 当前 LVM 状态 ===${NC}"
    
    # 检查逻辑卷
    if sudo lvs --noheadings 2>/dev/null | grep -q .; then
        sudo lvs 2>/dev/null
        echo ""
    else
        echo "  无逻辑卷"
        echo ""
    fi
    
    # 检查卷组
    if sudo vgs --noheadings 2>/dev/null | grep -q .; then
        sudo vgs 2>/dev/null
        echo ""
    else
        echo "  无卷组"
        echo ""
    fi
    
    # 检查物理卷
    if sudo pvs --noheadings 2>/dev/null | grep -q .; then
        sudo pvs 2>/dev/null
        echo ""
    else
        echo "  无物理卷"
        echo ""
    fi
}

# 函数:显示磁盘状态
show_disk_status() {
    echo -e "${BLUE}=== 当前磁盘状态 ===${NC}"
    lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT | grep -E "(sda|sdb|sdc|NAME)" | grep -v loop
    echo ""
}

# 函数:选择要卸载的卷组
select_vg_to_remove() {
    echo -e "${YELLOW}可用的卷组:${NC}"
    local vg_list=($(vgs --noheadings -o vg_name 2>/dev/null | tr -d ' ' 2>/dev/null))
    
    if [ ${#vg_list[@]} -eq 0 ]; then
        echo -e "${RED}未找到任何卷组${NC}"
        return 1
    fi
    
    for i in "${!vg_list[@]}"; do
        echo "  $((i+1)). ${vg_list[$i]}"
    done
    
    echo ""
    read -r -p "请选择要卸载的卷组 (输入数字): " choice
    
    local index=$((choice-1))
    if [ $index -ge 0 ] && [ $index -lt ${#vg_list[@]} ]; then
        selected_vg="${vg_list[$index]}"
        echo -e "${GREEN}选择: $selected_vg${NC}"
        return 0
    else
        echo -e "${RED}错误选择${NC}"
        return 1
    fi
}

# 函数:获取挂载点信息
get_mount_info() {
    local vg_name=$1
    local lv_name=$(lvs --noheadings -o lv_name "$vg_name" 2>/dev/null | tr -d ' ' 2>/dev/null)
    
    if [ -n "$lv_name" ]; then
        lv_path="/dev/$vg_name/$lv_name"
        mount_point=$(findmnt -n -o TARGET "$lv_path" 2>/dev/null)
        
        if [ -n "$mount_point" ]; then
            echo -e "${YELLOW}找到挂载点: $mount_point${NC}"
        else
            echo -e "${YELLOW}逻辑卷未挂载${NC}"
        fi
    fi
}

# 函数:获取卷组使用的物理卷
get_vg_physical_volumes() {
    local vg_name=$1
    pv_list=($(pvs --noheadings -o pv_name -S "vg_name=$vg_name" 2>/dev/null | tr -d ' ' 2>/dev/null))
    if [ ${#pv_list[@]} -gt 0 ]; then
        echo "卷组 $vg_name 使用的物理卷: ${pv_list[*]}"
    else
        echo "未找到卷组 $vg_name 的物理卷"
    fi
}

# 函数:确认清理选项
confirm_cleanup_option() {
    echo ""
    echo -e "${YELLOW}=== 磁盘清理选项 ===${NC}"
    if [ ${#pv_list[@]} -gt 0 ]; then
        echo "物理卷: ${pv_list[*]}"
    fi
    echo ""
    echo "选择清理级别:"
    echo "  1. 基本清理 (仅移除 LVM 配置)"
    echo "  2. 深度清理 (移除 LVM 配置并清理磁盘元数据,推荐)"
    echo "  3. 强制清理 (完全清理所有 LVM 残留)"
    echo ""
    read -r -p "请选择清理级别 (1/2/3, 默认 2): " cleanup_level
    
    case "${cleanup_level:-2}" in
        1)
            cleanup_type="basic"
            echo -e "${GREEN}选择: 基本清理${NC}"
            ;;
        2)
            cleanup_type="deep"
            echo -e "${GREEN}选择: 深度清理${NC}"
            ;;
        3)
            cleanup_type="force"
            echo -e "${GREEN}选择: 强制清理${NC}"
            ;;
        *)
            cleanup_type="deep"
            echo -e "${GREEN}选择: 深度清理 (默认)${NC}"
            ;;
    esac
}

# 函数:确认卸载
confirm_unmount() {
    echo ""
    echo -e "${YELLOW}=== 卸载摘要 ===${NC}"
    echo "卷组: $selected_vg"
    echo "挂载点: ${mount_point:-未挂载}"
    if [ ${#pv_list[@]} -gt 0 ]; then
        echo "物理卷: ${pv_list[*]}"
    fi
    echo "清理级别: $cleanup_type"
    echo ""
    echo -e "${RED}警告: 这将删除所有数据并解除 LVM 配置!${NC}"
    echo ""
    
    read -r -p "确认卸载?(输入 'YES' 继续): " confirm
    if [ "$confirm" != "YES" ]; then
        echo -e "${YELLOW}操作已取消${NC}"
        exit 0
    fi
}

# 函数:执行磁盘清理
perform_disk_cleanup() {
    local cleanup_type=$1
    shift
    local pv_list=("$@")
    
    echo -e "${GREEN}=== 执行磁盘清理 ===${NC}"
    
    for pv in "${pv_list[@]}"; do
        if [ ! -e "$pv" ]; then
            echo -e "  ${YELLOW}⚠ 设备 $pv 不存在,跳过${NC}"
            continue
        fi
        
        echo "清理 $pv ..."
        case $cleanup_type in
            "basic")
                # 基本清理:只移除 LVM 配置
                pvremove -y "$pv" 2>/dev/null || true
                echo -e "  ${GREEN}✓ 基本清理完成${NC}"
                ;;
            "deep"|"force")
                # 深度清理:移除所有文件系统签名
                pvremove -y "$pv" 2>/dev/null || true
                wipefs -a "$pv" 2>/dev/null || true
                dd if=/dev/zero of="$pv" bs=1M count=10 status=none 2>/dev/null || true
                echo -e "  ${GREEN}✓ 深度清理完成${NC}"
                ;;
        esac
    done
    
    # 如果是强制清理,执行额外清理步骤
    if [ "$cleanup_type" = "force" ]; then
        force_clean_lvm_residue
    fi
}

# 函数:执行卸载
perform_unmount() {
    local vg_name=$1
    local mount_point=$2
    local cleanup_type=$3
    shift 3
    local pv_list=("$@")
    
    echo -e "${GREEN}=== 开始卸载 LVM ===${NC}"
    
    # 1. 卸载文件系统
    if [ -n "$mount_point" ] && mountpoint -q "$mount_point" 2>/dev/null; then
        echo "步骤 1: 卸载文件系统..."
        if umount "$mount_point"; then
            echo -e "  ${GREEN}✓ 卸载成功${NC}"
        else
            echo -e "  ${YELLOW}⚠ 尝试强制卸载${NC}"
            umount -l "$mount_point" 2>/dev/null || true
            echo -e "  ${GREEN}✓ 强制卸载完成${NC}"
        fi
    else
        echo -e "  ${GREEN}✓ 文件系统未挂载${NC}"
    fi
    
    # 2. 移除 fstab 配置
    echo "步骤 2: 移除 fstab 配置..."
    if [ -n "$mount_point" ] && grep -q "$mount_point" /etc/fstab 2>/dev/null; then
        # 备份 fstab
        cp /etc/fstab "/etc/fstab.backup.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true
        sed -i "\|$mount_point|d" /etc/fstab
        echo -e "  ${GREEN}✓ fstab 配置已移除 (已备份)${NC}"
    else
        echo -e "  ${GREEN}✓ fstab 中无相关配置${NC}"
    fi
    
    # 3. 删除挂载点目录(可选)
    if [ -n "$mount_point" ] && [ -d "$mount_point" ]; then
        echo "步骤 3: 清理挂载点..."
        read -r -p "是否删除挂载点目录 $mount_point?(y/N): " remove_dir
        if [[ $remove_dir =~ ^[Yy]$ ]]; then
            rm -rf "$mount_point"
            echo -e "  ${GREEN}✓ 目录已删除${NC}"
        else
            echo -e "  ${YELLOW}⚠ 保留目录 $mount_point${NC}"
        fi
    fi
    
    # 4. 删除逻辑卷
    echo "步骤 4: 删除逻辑卷..."
    local lv_name=$(lvs --noheadings -o lv_name "$vg_name" 2>/dev/null | tr -d ' ' 2>/dev/null)
    if [ -n "$lv_name" ]; then
        if lvremove -f "$vg_name/$lv_name" 2>/dev/null; then
            echo -e "  ${GREEN}✓ 逻辑卷已删除${NC}"
        else
            echo -e "  ${YELLOW}⚠ 逻辑卷删除失败,尝试强制清理${NC}"
        fi
    else
        echo -e "  ${GREEN}✓ 无逻辑卷需要删除${NC}"
    fi
    
    # 5. 删除卷组
    echo "步骤 5: 删除卷组..."
    if vgremove "$vg_name" 2>/dev/null; then
        echo -e "  ${GREEN}✓ 卷组已删除${NC}"
    else
        echo -e "  ${YELLOW}⚠ 卷组删除失败,尝试强制清理${NC}"
    fi
    
    # 6. 执行磁盘清理
    if [ ${#pv_list[@]} -gt 0 ]; then
        perform_disk_cleanup "$cleanup_type" "${pv_list[@]}"
    fi
    
    # 7. 强制清理 LVM 残留(如果是强制清理模式)
    if [ "$cleanup_type" = "force" ]; then
        force_clean_lvm_residue
    fi
    
    return 0
}

# 函数:验证卸载结果
verify_unmount() {
    echo ""
    echo -e "${GREEN}=== 验证卸载结果 ===${NC}"
    
    local errors=0
    
    # 检查 LVM 配置
    echo "检查 LVM 配置..."
    if sudo lvs --noheadings 2>/dev/null | grep -q .; then
        echo -e "  ${RED}✗ 仍有逻辑卷存在${NC}"
        ((errors++))
    else
        echo -e "  ${GREEN}✓ 无逻辑卷${NC}"
    fi
    
    if sudo vgs --noheadings 2>/dev/null | grep -q .; then
        echo -e "  ${RED}✗ 仍有卷组存在${NC}"
        ((errors++))
    else
        echo -e "  ${GREEN}✓ 无卷组${NC}"
    fi
    
    if sudo pvs --noheadings 2>/dev/null | grep -q .; then
        echo -e "  ${RED}✗ 仍有物理卷存在${NC}"
        ((errors++))
    else
        echo -e "  ${GREEN}✓ 无物理卷${NC}"
    fi
    
    # 检查磁盘状态
    echo ""
    echo -e "${BLUE}=== 最终磁盘状态 ===${NC}"
    lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT | grep -E "(sda|sdb|sdc|NAME)"
    
    # 检查是否有 LVM2_member 残留
    if lsblk -o FSTYPE | grep -q "LVM2_member"; then
        echo -e "  ${YELLOW}⚠ 磁盘上仍有 LVM 元数据残留${NC}"
        ((errors++))
    else
        echo -e "  ${GREEN}✓ 磁盘元数据已清理${NC}"
    fi
    
    if [ $errors -eq 0 ]; then
        echo -e "${GREEN}✓ 所有 LVM 配置已完全清理${NC}"
    else
        echo -e "${YELLOW}⚠ 仍有 $errors 个问题需要处理${NC}"
    fi
    
    return $errors
}

# 主程序
main() {
    # 显示当前状态
    show_lvm_status
    show_disk_status
    
    # 选择要卸载的卷组
    if ! select_vg_to_remove; then
        echo -e "${YELLOW}未找到可卸载的卷组,检查磁盘残留...${NC}"
        # 检查是否有 LVM 元数据的磁盘
        lvm_disks=($(lsblk -o NAME,FSTYPE -n 2>/dev/null | grep "LVM2_member" | awk '{print $1}' 2>/dev/null))
        if [ ${#lvm_disks[@]} -gt 0 ]; then
            echo "发现带有 LVM 元数据的磁盘: ${lvm_disks[*]}"
            pv_list=()
            for disk in "${lvm_disks[@]}"; do
                pv_list+=("/dev/$disk")
            done
            confirm_cleanup_option
            perform_disk_cleanup "$cleanup_type" "${pv_list[@]}"
            verify_unmount
        else
            echo -e "${GREEN}系统已清理干净,无需操作${NC}"
        fi
        exit 0
    fi
    
    # 获取挂载点信息
    get_mount_info "$selected_vg"
    
    # 获取物理卷信息
    get_vg_physical_volumes "$selected_vg"
    
    # 确认清理选项
    confirm_cleanup_option
    
    # 确认操作
    confirm_unmount
    
    # 执行卸载
    if perform_unmount "$selected_vg" "$mount_point" "$cleanup_type" "${pv_list[@]}"; then
        echo ""
        echo -e "${GREEN}=== LVM 卸载完成 ===${NC}"
        echo "卷组 $selected_vg 已完全移除"
        echo "磁盘清理级别: $cleanup_type"
        echo "物理磁盘现在可以安全移除或重新使用"
    else
        echo -e "${RED}=== LVM 卸载失败 ===${NC}"
        exit 1
    fi
    
    # 验证结果
    verify_unmount
    
    # 如果仍有问题,建议重启
    if [ $? -ne 0 ]; then
        echo ""
        echo -e "${YELLOW}建议重启系统以确保完全清理 LVM 配置${NC}"
        read -r -p "是否立即重启系统?(y/N): " reboot_choice
        if [[ $reboot_choice =~ ^[Yy]$ ]]; then
            reboot
        fi
    fi
}

# 运行主程序
main "$@"

扩展 LVM 存储空间脚本lvm_extend.sh

又给服务器增加了一块盘,也要挂载到那个目录,保持原来挂载目录下的内容不要变

复制代码
#!/bin/bash

# LVM 扩展脚本
set -e

echo "=== LVM 存储扩展脚本 ==="
echo ""

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 检查 root 权限
if [ "$EUID" -ne 0 ]; then
    echo -e "${RED}错误: 请使用 sudo 运行此脚本${NC}"
    exit 1
fi

# 函数:显示当前状态
show_current_status() {
    echo -e "${GREEN}=== 当前 LVM 状态 ===${NC}"
    sudo lvs && echo ""
    sudo vgs && echo ""
    sudo pvs && echo ""
    
    echo -e "${BLUE}=== 当前磁盘状态 ===${NC}"
    lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT | grep -v loop
    echo ""
    
    echo -e "${YELLOW}=== 当前挂载状态 ===${NC}"
    df -h /home/mnt
    echo ""
}

# 函数:选择要扩展的卷组
select_vg_to_extend() {
    echo -e "${YELLOW}可用的卷组:${NC}"
    local vg_list=($(vgs --noheadings -o vg_name 2>/dev/null | tr -d ' '))
    
    if [ ${#vg_list[@]} -eq 0 ]; then
        echo -e "${RED}未找到任何卷组${NC}"
        exit 1
    fi
    
    for i in "${!vg_list[@]}"; do
        vg_size=$(vgs --noheadings -o vg_size "$vg_name" 2>/dev/null)
        echo "  $((i+1)). ${vg_list[$i]} ($vg_size)"
    done
    
    echo ""
    read -r -p "请选择要扩展的卷组 (输入数字): " choice
    
    local index=$((choice-1))
    if [ $index -ge 0 ] && [ $index -lt ${#vg_list[@]} ]; then
        selected_vg="${vg_list[$index]}"
        echo -e "${GREEN}选择: $selected_vg${NC}"
    else
        echo -e "${RED}错误选择${NC}"
        exit 1
    fi
}

# 函数:选择新磁盘
select_new_disk() {
    echo -e "${YELLOW}可用的新磁盘:${NC}"
    
    # 获取所有未使用的磁盘
    available_disks=()
    while IFS= read -r line; do
        disk_name=$(echo "$line" | awk '{print $1}')
        disk_type=$(echo "$line" | awk '{print $3}')
        mountpoint=$(echo "$line" | awk '{print $4}')
        fstype=$(echo "$line" | awk '{print $5}')
        
        # 检查是否是磁盘类型且未挂载、无文件系统、不是 LVM 成员
        if [ "$disk_type" == "disk" ] && [ -z "$mountpoint" ] && [ -z "$fstype" ] && \
           [ "$disk_name" != "NAME" ] && ! lsblk "/dev/$disk_name" | grep -q "/$"; then
            # 检查是否已经在 LVM 中
            if ! pvs | grep -q "/dev/$disk_name"; then
                available_disks+=("$disk_name")
            fi
        fi
    done < <(lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE | tail -n +2)
    
    if [ ${#available_disks[@]} -eq 0 ]; then
        echo -e "${RED}未找到可用的新磁盘!${NC}"
        exit 1
    fi
    
    for i in "${!available_disks[@]}"; do
        disk_size=$(lsblk -b -d -o NAME,SIZE "/dev/${available_disks[$i]}" | grep "^${available_disks[$i]}" | awk '{print $2}')
        size_gb=$(echo "scale=2; $disk_size/1024/1024/1024" | bc)
        echo "  $((i+1)). /dev/${available_disks[$i]} (${size_gb} GB)"
    done
    
    echo ""
    read -r -p "请选择要添加的新磁盘 (输入数字): " choice
    
    local index=$((choice-1))
    if [ $index -ge 0 ] && [ $index -lt ${#available_disks[@]} ]; then
        new_disk="/dev/${available_disks[$index]}"
        echo -e "${GREEN}选择: $new_disk${NC}"
    else
        echo -e "${RED}错误选择${NC}"
        exit 1
    fi
}

# 函数:确认扩展操作
confirm_extend() {
    echo ""
    echo -e "${YELLOW}=== 扩展摘要 ===${NC}"
    echo "卷组: $selected_vg"
    echo "新磁盘: $new_disk"
    echo "挂载点: /home/mnt"
    echo ""
    echo -e "${GREEN}优势: 现有数据将完全保留,无需迁移!${NC}"
    echo ""
    
    read -r -p "确认扩展操作?(输入 'YES' 继续): " confirm
    if [ "$confirm" != "YES" ]; then
        echo -e "${YELLOW}操作已取消${NC}"
        exit 0
    fi
}

# 函数:执行扩展
perform_extend() {
    local vg_name=$1
    local new_disk=$2
    
    echo -e "${GREEN}=== 开始扩展 LVM ===${NC}"
    
    # 1. 创建新物理卷
    echo "步骤 1: 创建新物理卷..."
    if pvcreate "$new_disk"; then
        echo -e "  ${GREEN}✓ 物理卷创建成功${NC}"
    else
        echo -e "  ${RED}✗ 物理卷创建失败${NC}"
        return 1
    fi
    
    # 2. 扩展卷组
    echo "步骤 2: 扩展卷组..."
    if vgextend "$vg_name" "$new_disk"; then
        echo -e "  ${GREEN}✓ 卷组扩展成功${NC}"
    else
        echo -e "  ${RED}✗ 卷组扩展失败${NC}"
        return 1
    fi
    
    # 3. 扩展逻辑卷(使用全部新空间)
    echo "步骤 3: 扩展逻辑卷..."
    local lv_name=$(lvs --noheadings -o lv_name "$vg_name" | tr -d ' ')
    if lvextend -l +100%FREE "/dev/$vg_name/$lv_name"; then
        echo -e "  ${GREEN}✓ 逻辑卷扩展成功${NC}"
    else
        echo -e "  ${RED}✗ 逻辑卷扩展失败${NC}"
        return 1
    fi
    
    # 4. 扩展文件系统(在线扩展,无需卸载)
    echo "步骤 4: 扩展文件系统..."
    local fs_type=$(df -T /home/mnt | awk 'NR==2 {print $2}')
    
    if [ "$fs_type" == "ext4" ]; then
        # 对于 ext4 文件系统
        if resize2fs "/dev/$vg_name/$lv_name"; then
            echo -e "  ${GREEN}✓ 文件系统扩展成功${NC}"
        else
            echo -e "  ${RED}✗ 文件系统扩展失败${NC}"
            return 1
        fi
    elif [ "$fs_type" == "xfs" ]; then
        # 对于 xfs 文件系统
        if xfs_growfs "/home/mnt"; then
            echo -e "  ${GREEN}✓ 文件系统扩展成功${NC}"
        else
            echo -e "  ${RED}✗ 文件系统扩展失败${NC}"
            return 1
        fi
    else
        echo -e "  ${YELLOW}⚠ 未知文件系统类型: $fs_type,请手动扩展${NC}"
    fi
    
    return 0
}

# 主程序
main() {
    # 显示当前状态
    show_current_status
    
    # 选择要扩展的卷组
    select_vg_to_extend
    
    # 选择新磁盘
    select_new_disk
    
    # 确认操作
    confirm_extend
    
    # 执行扩展
    if perform_extend "$selected_vg" "$new_disk"; then
        echo ""
        echo -e "${GREEN}=== LVM 扩展完成 ===${NC}"
        echo "卷组 $selected_vg 已成功扩展"
        echo "新磁盘 $new_disk 已添加到存储池"
        echo ""
        echo -e "${BLUE}扩展后的状态:${NC}"
        df -h /home/mnt
        echo ""
        sudo vgs "$selected_vg"
    else
        echo -e "${RED}=== LVM 扩展失败 ===${NC}"
        exit 1
    fi
}

# 运行主程序
main "$@"
相关推荐
L_09071 分钟前
【Linux】进程状态
linux·开发语言·c++
啟明起鸣2 分钟前
【Nginx 网关开发】上手 Nginx,简简单单启动一个静态 html 页面
运维·c语言·前端·nginx·html
小生不才yz5 分钟前
shell编程 - 数据流指南
linux
好奇的菜鸟8 分钟前
Ubuntu 18.04 启用root账户图形界面登录指南
数据库·ubuntu·postgresql
lisanmengmeng10 分钟前
添加ceph节点
linux·服务器·ceph
Tinyundg14 分钟前
Linux系统分区
linux·运维·服务器
要做一个小太阳17 分钟前
华为Atlas 900 A3 SuperPoD 超节点网络架构
运维·服务器·网络·华为·架构
江畔何人初21 分钟前
service发现
linux·运维·云原生
life码农27 分钟前
Linux系统清空文件内容的几种方法
linux·运维·chrome
zbguolei32 分钟前
虚拟机安装Ubuntu后无法登录
linux·运维·ubuntu