Linux / 操作系统
磁盘挂载脚本(支持LVM和直接挂载)
磁盘挂载脚本(支持LVM和直接挂载)
BASH
上生产前,先在测试库跑一遍,确认版本、权限和影响范围。涉及数据或配置变更时,先备份,备好回退方案。
脚本使用说明
这些脚本供学习和日常运维参考。执行前请自行验证脚本是否适合你的环境,做好必要备份,并承担执行风险。因使用脚本造成的损失,本站在法律允许的范围内不承担责任。依法应承担的责任仍由本站承担。
community-cab6b146-5e56-4091-9ef0-48a68da77b47.sh
使用方式
挂载方式说明: lvm - 使用LVM方式挂载(创建PV、VG、LV),通过-f参数指定文件系统类型 direct - 直接格式化整个磁盘并挂载,通过-f参数指定文件系统类型
示例: # LVM模式挂载XFS $0 -d /dev/sdc -m /mnt/data -t lvm -v myvg -l mylv -f xfs
# 直接挂载XFS格式 $0 -d /dev/sdc -m /mnt/data -t direct -f xfs
# 直接挂载EXT4格式 $0 -d /dev/nvme0n1 -m /storage -t direct -f ext4
# LVM模式挂载EXT4(默认) $0 -d /dev/sdb -m /backup -t lvm
完整脚本
Linux · bash
#!/bin/bash
# 磁盘挂载脚本(支持LVM和直接挂载)
# 用法: ./mount_lvm_disk.sh [选项]
# 选项:
# -d, --disk DISK 指定磁盘设备 (必须参数)
# -m, --mount MOUNT_POINT 指定挂载点 (默认: /data)
# -t, --type TYPE 挂载方式: lvm 或 direct (默认: lvm)
# -v, --vgname VG_NAME 指定卷组名称 (默认: data, 仅LVM模式)
# -l, --lvname LV_NAME 指定逻辑卷名称 (默认: data_lv, 仅LVM模式)
# -f, --fstype FS_TYPE 指定文件系统类型: xfs, ext4, ext3 (默认: ext4)
# -h, --help 显示帮助信息
set -e
# 默认参数
DISK=""
MOUNT_POINT="/data"
MOUNT_TYPE="lvm"
VG_NAME="data"
LV_NAME="data_lv"
FS_TYPE="ext4"
# 显示帮助信息
show_help() {
cat << EOF
磁盘挂载脚本(支持LVM和直接挂载)
用法: $0 [选项]
选项:
-d, --disk DISK 指定磁盘设备 (必须参数)
-m, --mount MOUNT_POINT 指定挂载点 (默认: $MOUNT_POINT)
-t, --type TYPE 挂载方式: lvm 或 direct (默认: $MOUNT_TYPE)
-v, --vgname VG_NAME 指定卷组名称 (默认: $VG_NAME, 仅LVM模式)
-l, --lvname LV_NAME 指定逻辑卷名称 (默认: $LV_NAME, 仅LVM模式)
-f, --fstype FS_TYPE 指定文件系统类型: xfs, ext4, ext3 (默认: $FS_TYPE)
-h, --help 显示帮助信息
挂载方式说明:
lvm - 使用LVM方式挂载(创建PV、VG、LV),通过-f参数指定文件系统类型
direct - 直接格式化整个磁盘并挂载,通过-f参数指定文件系统类型
示例:
# LVM模式挂载XFS
$0 -d /dev/sdc -m /mnt/data -t lvm -v myvg -l mylv -f xfs
# 直接挂载XFS格式
$0 -d /dev/sdc -m /mnt/data -t direct -f xfs
# 直接挂载EXT4格式
$0 -d /dev/nvme0n1 -m /storage -t direct -f ext4
# LVM模式挂载EXT4(默认)
$0 -d /dev/sdb -m /backup -t lvm
EOF
}
# 解析命令行参数
parse_args() {
# 如果没有提供任何参数,显示帮助
if [ $# -eq 0 ]; then
show_help
exit 0
fi
while [[ $# -gt 0 ]]; do
case $1 in
-d|--disk)
DISK="$2"
shift 2
;;
-m|--mount)
MOUNT_POINT="$2"
shift 2
;;
-t|--type)
MOUNT_TYPE="$2"
shift 2
;;
-v|--vgname)
VG_NAME="$2"
shift 2
;;
-l|--lvname)
LV_NAME="$2"
shift 2
;;
-f|--fstype)
FS_TYPE="$2"
shift 2
;;
-h|--help)
show_help
exit 0
;;
*)
echo "错误:未知选项: $1" >&2
show_help
exit 1
;;
esac
done
# 检查必须参数
if [ -z "$DISK" ]; then
echo "错误:必须指定磁盘设备 (-d/--disk 参数)" >&2
show_help
exit 1
fi
# 检查挂载方式
if [[ "$MOUNT_TYPE" != "lvm" && "$MOUNT_TYPE" != "direct" ]]; then
echo "错误:挂载方式必须是 'lvm' 或 'direct'" >&2
show_help
exit 1
fi
# 检查文件系统类型
if [[ "$FS_TYPE" != "xfs" && "$FS_TYPE" != "ext4" && "$FS_TYPE" != "ext3" ]]; then
echo "错误:文件系统类型必须是 'xfs'、'ext4' 或 'ext3'" >&2
show_help
exit 1
fi
}
# 检查是否以root权限运行
check_root() {
if [ "$(id -u)" != "0" ]; then
echo "错误:此脚本必须以root权限运行" >&2
exit 1
fi
}
# 检查磁盘是否存在和是否已被分区
check_disk() {
if [ ! -b "$DISK" ]; then
echo "错误:磁盘 $DISK 不存在" >&2
exit 1
fi
# 更准确的分区检查:使用lsblk检查是否有子分区
if lsblk "$DISK" 2>/dev/null | grep -q "part"; then
echo "错误:磁盘 $DISK 已有分区,操作已中止" >&2
echo "请确认磁盘设备正确,或使用未分区的磁盘" >&2
echo "当前分区情况:"
lsblk "$DISK"
exit 1
fi
# 检查磁盘是否已被LVM使用
if lsblk "$DISK" | grep -q "lvm"; then
echo "错误:磁盘 $DISK 似乎已被LVM使用,操作已中止" >&2
exit 1
fi
# 检查磁盘是否已被挂载
if mount | grep -q "$DISK"; then
echo "错误:磁盘 $DISK 已被挂载,操作已中止" >&2
exit 1
fi
# 检查磁盘是否已经是PV
if pvdisplay "$DISK" >/dev/null 2>&1; then
echo "错误:磁盘 $DISK 已经是LVM物理卷,操作已中止" >&2
exit 1
fi
}
# 确认操作
confirm_operation() {
echo "警告:此操作将完全清除磁盘 $DISK 上的所有数据!"
echo "请确认以下信息:"
echo " 磁盘设备: $DISK"
echo " 磁盘大小: $(lsblk -d -o SIZE "$DISK" 2>/dev/null | tail -1)"
echo " 挂载类型: $MOUNT_TYPE"
echo " 挂载点: $MOUNT_POINT"
if [ "$MOUNT_TYPE" == "lvm" ]; then
echo " 卷组名称: $VG_NAME"
echo " 逻辑卷名称: $LV_NAME"
fi
echo " 文件系统类型: $FS_TYPE"
echo
echo "磁盘当前状态:"
lsblk "$DISK"
echo
read -p "是否继续?(输入 'YES' 确认): " -r
if [[ ! $REPLY == "YES" ]]; then
echo "操作已取消"
exit 0
fi
}
# 清理磁盘并创建物理卷
create_pv() {
echo "清理磁盘 $DISK..."
# 清除磁盘上的所有数据结构(分区表、文件系统签名等)
wipefs -a "$DISK" >/dev/null 2>&1 || true
# 清零分区表
dd if=/dev/zero of="$DISK" bs=1M count=10 >/dev/null 2>&1 || true
# 通知内核重新读取分区表
partprobe "$DISK" >/dev/null 2>&1 || true
echo "创建物理卷 $DISK..."
if ! pvcreate "$DISK"; then
echo "错误:创建物理卷失败" >&2
exit 1
fi
}
# 创建卷组
create_vg() {
echo "创建卷组 $VG_NAME..."
# 检查卷组是否已存在
if vgdisplay "$VG_NAME" >/dev/null 2>&1; then
echo "错误:卷组 $VG_NAME 已存在" >&2
echo "请使用不同的卷组名称或删除现有卷组"
exit 1
fi
if ! vgcreate "$VG_NAME" "$DISK"; then
echo "错误:创建卷组失败" >&2
exit 1
fi
}
# 创建逻辑卷
create_lv() {
echo "创建逻辑卷 $LV_NAME..."
# 检查逻辑卷是否已存在
if lvdisplay "/dev/$VG_NAME/$LV_NAME" >/dev/null 2>&1; then
echo "错误:逻辑卷 $LV_NAME 在卷组 $VG_NAME 中已存在" >&2
exit 1
fi
if ! lvcreate -n "$LV_NAME" -l "100%FREE" "$VG_NAME"; then
echo "错误:创建逻辑卷失败" >&2
exit 1
fi
}
# 格式化文件系统
format_fs() {
echo "格式化文件系统为 $FS_TYPE..."
# 根据文件系统类型选择格式化命令
case $FS_TYPE in
ext4)
mkfs_cmd="mkfs.ext4"
;;
xfs)
mkfs_cmd="mkfs.xfs -f"
;;
ext3)
mkfs_cmd="mkfs.ext3"
;;
*)
echo "错误:不支持的文件系统类型: $FS_TYPE" >&2
exit 1
;;
esac
# 根据挂载类型选择设备路径
if [ "$MOUNT_TYPE" == "lvm" ]; then
DEVICE_PATH="/dev/mapper/$VG_NAME-$LV_NAME"
else
DEVICE_PATH="$DISK"
fi
if ! $mkfs_cmd "$DEVICE_PATH"; then
echo "错误:格式化文件系统失败" >&2
exit 1
fi
}
# 创建挂载点
create_mount_point() {
echo "创建挂载点 $MOUNT_POINT..."
mkdir -p "$MOUNT_POINT"
}
# 更新fstab
update_fstab() {
echo "获取文件系统UUID..."
# 等待设备稳定
sleep 2
sync
# 根据挂载类型选择设备路径
if [ "$MOUNT_TYPE" == "lvm" ]; then
TARGET_DEVICE="/dev/mapper/$VG_NAME-$LV_NAME"
else
TARGET_DEVICE="$DISK"
fi
UUID=$(blkid -o value -s UUID "$TARGET_DEVICE" 2>/dev/null)
if [ -z "$UUID" ]; then
echo "警告:无法获取UUID,将使用设备路径" >&2
DEVICE_PATH="$TARGET_DEVICE"
else
DEVICE_PATH="UUID=$UUID"
fi
echo "更新/etc/fstab..."
# 备份fstab
backup_file="/etc/fstab.bak.$(date +%Y%m%d%H%M%S)"
cp /etc/fstab "$backup_file"
echo "已创建备份: $backup_file"
# 删除现有条目(如果存在)
if grep -q "$MOUNT_POINT" /etc/fstab; then
echo "警告:/etc/fstab中已存在$MOUNT_POINT的挂载配置,将替换现有条目"
sed -i "\|$MOUNT_POINT|d" /etc/fstab
fi
# 添加新条目
echo "$DEVICE_PATH $MOUNT_POINT $FS_TYPE defaults 0 2" >> /etc/fstab
}
# 挂载文件系统
mount_fs() {
echo "挂载文件系统..."
if ! mount -a; then
echo "错误:挂载失败" >&2
exit 1
fi
}
# 验证挂载
verify_mount() {
if mountpoint -q "$MOUNT_POINT"; then
echo "成功:磁盘已挂载到 $MOUNT_POINT"
echo
echo "挂载信息:"
df -h "$MOUNT_POINT"
echo
if [ "$MOUNT_TYPE" == "lvm" ]; then
echo "LVM信息:"
echo "物理卷:$(pvdisplay "$DISK" 2>/dev/null | grep "PV Name" | awk '{print $3}')"
echo "卷组:$(vgdisplay "$VG_NAME" 2>/dev/null | grep "VG Name" | awk '{print $3}')"
echo "逻辑卷:$(lvdisplay "/dev/$VG_NAME/$LV_NAME" 2>/dev/null | grep "LV Name" | awk '{print $3}')"
else
echo "磁盘信息:"
lsblk "$DISK" -o NAME,SIZE,FSTYPE,MOUNTPOINT
fi
else
echo "错误:挂载验证失败" >&2
exit 1
fi
}
# 直接挂载模式(清理并格式化整个磁盘)
direct_mount_mode() {
echo "清理磁盘 $DISK..."
# 清除磁盘上的所有数据结构(分区表、文件系统签名等)
wipefs -a "$DISK" >/dev/null 2>&1 || true
# 清零分区表
dd if=/dev/zero of="$DISK" bs=1M count=10 >/dev/null 2>&1 || true
# 通知内核重新读取分区表
partprobe "$DISK" >/dev/null 2>&1 || true
format_fs
create_mount_point
update_fstab
mount_fs
verify_mount
}
# LVM挂载模式
lvm_mount_mode() {
create_pv
create_vg
create_lv
format_fs
create_mount_point
update_fstab
mount_fs
verify_mount
}
# 主函数
main() {
parse_args "$@"
if [ "$MOUNT_TYPE" == "lvm" ]; then
echo "开始执行LVM磁盘挂载操作($FS_TYPE文件系统)..."
else
echo "开始执行直接磁盘挂载操作($FS_TYPE文件系统)..."
fi
echo
check_root
check_disk
confirm_operation
if [ "$MOUNT_TYPE" == "lvm" ]; then
lvm_mount_mode
echo "LVM磁盘挂载操作完成!"
else
direct_mount_mode
echo "直接磁盘挂载操作完成!"
fi
}
# 执行主函数
main "$@"