挂载脚本 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 "$@"