扩展空间脚本优化记录
侧边栏壁纸
  • 累计撰写 19 篇文章
  • 累计收到 2 条评论

扩展空间脚本优化记录

admin
2025-08-29 / 0 评论 / 3 阅读 / 正在检测是否收录...

我帮你修改脚本,将 DISK="/dev/mmcblk0"ROOT_PARTITION="${DISK}p5" 替换为通过 findmnt -no SOURCE / 动态获取根分区设备路径,同时保持其他功能不变。以下是完整的修改后脚本代码:

#!/bin/bash

# 日志文件
LOG_FILE="/var/log/expand_root_and_swapfile.log"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "===== 根分区扩展与交换文件创建脚本开始执行: $(date) ====="

# 检查是否以 root 用户运行
if [ "$(id -u)" != "0" ]; then
    echo "错误:此脚本需要以 root 权限运行,请使用 sudo 或切换到 root 用户。"
    exit 1
fi

# 检查必要工具是否安装(扩展分区和文件系统所需的工具)
if ! command -v parted >/dev/null 2>&1; then
    echo "错误:parted 未安装,请先安装 parted(例如:apt install parted)。"
    exit 1
fi
if ! command -v resize2fs >/dev/null 2>&1; then
    echo "错误:resize2fs 未安装,请先安装 e2fsprogs(例如:apt install e2fsprogs)。"
    exit 1
fi
if ! command -v expect >/dev/null 2>&1; then
    echo "错误:expect 未安装,请先安装 expect(例如:apt install expect)。"
    exit 1
fi
if ! command -v partprobe >/dev/null 2>&1; then
    echo "错误:partprobe 未安装,请先安装 parted(例如:apt install parted)。"
    exit 1
fi
if ! command -v fsck >/dev/null 2>&1; then
    echo "错误:fsck 未安装,请先安装 e2fsprogs(例如:apt install e2fsprogs)。"
    exit 1
fi

# 定义交换文件和大小
SWAP_FILE="/swapfile"
SWAP_SIZE_MB=512

# 通过 findmnt 获取根分区设备路径
ROOT_PARTITION=$(findmnt -no SOURCE /)
if [ -z "$ROOT_PARTITION" ]; then
    echo "错误:无法通过 findmnt 获取根分区设备路径,请检查系统配置。"
    exit 1
fi

# 从根分区路径推导磁盘设备路径(例如 /dev/mmcblk0p5 -> /dev/mmcblk0)
DISK=$(echo "$ROOT_PARTITION" | sed -r 's/p[0-9]+$//')
if [ -z "$DISK" ]; then
    echo "错误:无法从根分区路径 $ROOT_PARTITION 推导磁盘设备路径。"
    exit 1
fi

# 检查磁盘是否存在
if [ ! -b "$DISK" ]; then
    echo "错误:磁盘 $DISK 不存在,请检查设备名称。"
    exit 1
fi

# 检查根分区是否存在
if [ ! -b "$ROOT_PARTITION" ]; then
    echo "错误:根分区 $ROOT_PARTITION 不存在,请检查分区编号。"
    exit 1
fi

# 检查根分区是否挂载
MOUNT_POINT=$(mount | grep "$ROOT_PARTITION" | awk '{print $3}')
if [ -z "$MOUNT_POINT" ]; then
    echo "错误:根分区 $ROOT_PARTITION 未挂载,请确保分区已挂载。"
    exit 1
fi
echo "根分区 $ROOT_PARTITION 已挂载到 $MOUNT_POINT,可以在线扩展。"

# 显示分区表和可用空间
echo "正在检查磁盘 $DISK 的分区布局..."
parted -s "$DISK" unit MB print free

# 验证根分区是否为最后一个分区且后面有可用空间
FREE_SPACE=$(parted -s "$DISK" unit MB print free | grep -A1 "Number.*Start.*End.*Size" | tail -n 1 | grep "Free Space")
if [ -z "$FREE_SPACE" ]; then
    echo "错误:根分区 $ROOT_PARTITION 后面没有可用空间,无法扩展。"
    exit 1
fi

# 使用 expect 自动运行 parted,模拟手动步骤:print free -> Fix -> resizepart [分区号] 100% -> quit
PARTITION_NUMBER=$(echo "$ROOT_PARTITION" | grep -o '[0-9]\+$')
if [ -z "$PARTITION_NUMBER" ]; then
    echo "错误:无法从根分区路径 $ROOT_PARTITION 提取分区号。"
    exit 1
fi
echo "正在运行 parted,自动输入 'Fix' 并调整根分区大小..."
/usr/bin/expect <<EOF
set timeout 30
spawn parted $DISK
expect "(parted)" {
    send "print free\r"
    expect {
        "Fix/Ignore?" {
            send "Fix\r"
            expect "(parted)" {
                send "resizepart $PARTITION_NUMBER 100%\r"
                expect "(parted)" {
                    send "quit\r"
                }
            }
        }
        "(parted)" {
            send "resizepart $PARTITION_NUMBER 100%\r"
            expect "(parted)" {
                send "quit\r"
            }
        }
        timeout {
            send_user "错误:parted 交互超时\n"
            exit 1
        }
    }
}
expect eof
EOF

if [ $? -ne 0 ]; then
    echo "错误:parted 执行失败,请检查日志 $LOG_FILE。"
    exit 1
fi

# 通知内核更新分区表
echo "正在通知内核更新分区表..."
partprobe "$DISK" || {
    echo "错误:partprobe 失败,尝试使用 blockdev 同步..."
    blockdev --rereadpt "$DISK" || {
        echo "错误:分区表同步失败,请检查日志 $LOG_FILE。"
        exit 1
    }
}

# 显示调整后的分区表
echo "根分区调整完成,以下是新的分区布局:"
parted -s "$DISK" unit MB print free

# 检查文件系统一致性(非破坏性检查)
echo "正在检查文件系统一致性(非破坏性)..."
fsck -n "$ROOT_PARTITION" || {
    echo "警告:文件系统检查发现问题,建议手动运行 'e2fsck -f $ROOT_PARTITION' 修复(需卸载或重启到单用户模式)。"
    echo "继续尝试在线扩展文件系统..."
}

# 执行文件系统扩展
echo "正在扩展根分区文件系统..."
resize2fs "$ROOT_PARTITION" || {
    echo "错误:文件系统扩展失败,请检查日志 $LOG_FILE。"
    echo "可能需要手动运行 'e2fsck -f $ROOT_PARTITION' 和 'resize2fs $ROOT_PARTITION'。"
    exit 1
}

# 显示扩展后的文件系统信息
echo "根分区文件系统扩展完成!以下是新的文件系统信息:"
df -h | grep "$ROOT_PARTITION"

# 检查交换文件相关工具和空间
echo "正在检查交换文件创建所需的工具和空间..."
if ! command -v mkswap >/dev/null 2>&1; then
    echo "错误:mkswap 未安装,请先安装 util-linux(例如:apt install util-linux)。"
    exit 1
fi

# 检查扩展后根文件系统可用空间是否足够创建 512MB 交换文件
FREE_SPACE_MB=$(df --block-size=1M "$MOUNT_POINT" | tail -n 1 | awk '{print $4}')
if [ -z "$FREE_SPACE_MB" ]; then
    echo "错误:无法获取扩展后根文件系统可用空间,请检查 df 命令输出。"
    exit 1
fi
if [ "$FREE_SPACE_MB" -lt "$SWAP_SIZE_MB" ]; then
    echo "错误:扩展后根文件系统可用空间 ($FREE_SPACE_MB MB) 小于所需的交换文件大小 ($SWAP_SIZE_MB MB)。"
    exit 1
fi
echo "扩展后根文件系统可用空间为 $FREE_SPACE_MB MB,足以创建 $SWAP_SIZE_MB MB 交换文件。"

# 创建交换文件
echo "正在创建 $SWAP_SIZE_MB MB 交换文件 ($SWAP_FILE)..."
if [ -f "$SWAP_FILE" ]; then
    echo "交换文件 $SWAP_FILE 已存在,跳过创建。"
else
    dd if=/dev/zero of="$SWAP_FILE" bs=1M count="$SWAP_SIZE_MB" status=progress || {
        echo "错误:创建交换文件失败,请检查日志 $LOG_FILE。"
        exit 1
    }
    chmod 600 "$SWAP_FILE" || {
        echo "错误:设置交换文件权限失败,请检查日志 $LOG_FILE。"
        exit 1
    }
    mkswap "$SWAP_FILE" || {
        echo "错误:格式化交换文件失败,请检查日志 $LOG_FILE。"
        exit 1
    }
fi

# 启用交换文件
echo "正在启用交换文件..."
swapon "$SWAP_FILE" || {
    echo "错误:启用交换文件失败,请检查日志 $LOG_FILE。"
    exit 1
}

# 添加交换文件到 fstab
echo "正在将交换文件添加到 /etc/fstab..."
if ! grep -q "$SWAP_FILE" /etc/fstab; then
    echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab
    echo "交换文件已添加到 /etc/fstab。"
else
    echo "交换文件已在 /etc/fstab 中,无需重复添加。"
fi

# 显示交换空间状态
echo "交换文件创建并启用完成!以下是交换空间信息:"
swapon --show

# 禁用脚本以防止下次启动重复执行
systemctl disable auto-expand-root.service
echo "脚本已完成并禁用自动执行,避免重复运行。"

echo "===== 根分区扩展与交换文件创建脚本执行完成: $(date) ====="

修改说明

  1. 动态获取根分区

    • 使用 ROOT_PARTITION=$(findmnt -no SOURCE /) 获取根分区的设备路径(如 /dev/mmcblk0p5)。
    • 添加了错误检查,确保 findmnt 能正确返回根分区路径。
  2. 推导磁盘设备路径

    • 从根分区路径(如 /dev/mmcblk0p5)通过 sed -r 's/p[0-9]+$//' 提取磁盘设备路径(如 /dev/mmcblk0)。
    • 添加了错误检查,确保能正确提取磁盘路径。
  3. 动态获取分区号

    • partedresizepart 命令中,使用 PARTITION_NUMBER=$(echo "$ROOT_PARTITION" | grep -o '[0-9]\+$') 提取分区号(如 5),以动态调整根分区。
    • 添加了错误检查,确保能正确提取分区号。
  4. 其他部分保持不变

    • 保留了原脚本的所有功能,包括日志记录、分区扩展、文件系统扩展、交换文件创建等。
    • 错误提示和日志输出中的设备路径已更新为动态获取的 $ROOT_PARTITION$DISK

注意事项

  • 脚本假设根分区是最后一个分区且后面有可用空间。如果实际情况不同,可能需要进一步调整逻辑。
  • 确保 findmnt 命令可用(通常包含在 util-linux 包中)。
  • 如果根分区路径格式非标准(如不是 /dev/mmcblk0pX 形式),sed 提取磁盘路径的逻辑可能需要调整。

原脚本:

#!/bin/bash

# 日志文件
LOG_FILE="/var/log/expand_root_and_swapfile.log"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "===== 根分区扩展与交换文件创建脚本开始执行: $(date) ====="

# 检查是否以 root 用户运行
if [ "$(id -u)" != "0" ]; then
    echo "错误:此脚本需要以 root 权限运行,请使用 sudo 或切换到 root 用户。"
    exit 1
fi

# 检查必要工具是否安装(扩展分区和文件系统所需的工具)
if ! command -v parted >/dev/null 2>&1; then
    echo "错误:parted 未安装,请先安装 parted(例如:apt install parted)。"
    exit 1
fi
if ! command -v resize2fs >/dev/null 2>&1; then
    echo "错误:resize2fs 未安装,请先安装 e2fsprogs(例如:apt install e2fsprogs)。"
    exit 1
fi
if ! command -v expect >/dev/null 2>&1; then
    echo "错误:expect 未安装,请先安装 expect(例如:apt install expect)。"
    exit 1
fi
if ! command -v partprobe >/dev/null 2>&1; then
    echo "错误:partprobe 未安装,请先安装 parted(例如:apt install parted)。"
    exit 1
fi
if ! command -v fsck >/dev/null 2>&1; then
    echo "错误:fsck 未安装,请先安装 e2fsprogs(例如:apt install e2fsprogs)。"
    exit 1
fi

# 定义目标磁盘、分区和交换文件
DISK="/dev/mmcblk0"
ROOT_PARTITION="${DISK}p5"
SWAP_FILE="/swapfile"
SWAP_SIZE_MB=512

# 检查磁盘是否存在
if [ ! -b "$DISK" ]; then
    echo "错误:磁盘 $DISK 不存在,请检查设备名称。"
    exit 1
fi

# 检查根分区是否存在
if [ ! -b "$ROOT_PARTITION" ]; then
    echo "错误:根分区 $ROOT_PARTITION 不存在,请检查分区编号。"
    exit 1
fi

# 检查根分区是否挂载
MOUNT_POINT=$(mount | grep "$ROOT_PARTITION" | awk '{print $3}')
if [ -z "$MOUNT_POINT" ]; then
    echo "错误:根分区 $ROOT_PARTITION 未挂载,请确保分区已挂载。"
    exit 1
fi
echo "根分区 $ROOT_PARTITION 已挂载到 $MOUNT_POINT,可以在线扩展。"

# 显示分区表和可用空间
echo "正在检查磁盘 $DISK 的分区布局..."
parted -s "$DISK" unit MB print free

# 验证根分区是否为最后一个分区且后面有可用空间
FREE_SPACE=$(parted -s "$DISK" unit MB print free | grep -A1 "Number.*Start.*End.*Size" | tail -n 1 | grep "Free Space")
if [ -z "$FREE_SPACE" ]; then
    echo "错误:根分区 $ROOT_PARTITION 后面没有可用空间,无法扩展。"
    exit 1
fi

# 使用 expect 自动运行 parted,模拟手动步骤:print free -> Fix -> resizepart 5 100% -> quit
echo "正在运行 parted,自动输入 'Fix' 并调整根分区大小..."
/usr/bin/expect <<EOF
set timeout 30
spawn parted $DISK
expect "(parted)" {
    send "print free\r"
    expect {
        "Fix/Ignore?" {
            send "Fix\r"
            expect "(parted)" {
                send "resizepart 5 100%\r"
                expect "(parted)" {
                    send "quit\r"
                }
            }
        }
        "(parted)" {
            send "resizepart 5 100%\r"
            expect "(parted)" {
                send "quit\r"
            }
        }
        timeout {
            send_user "错误:parted 交互超时\n"
            exit 1
        }
    }
}
expect eof
EOF

if [ $? -ne 0 ]; then
    echo "错误:parted 执行失败,请检查日志 $LOG_FILE。"
    exit 1
fi

# 通知内核更新分区表
echo "正在通知内核更新分区表..."
partprobe "$DISK" || {
    echo "错误:partprobe 失败,尝试使用 blockdev 同步..."
    blockdev --rereadpt "$DISK" || {
        echo "错误:分区表同步失败,请检查日志 $LOG_FILE。"
        exit 1
    }
}

# 显示调整后的分区表
echo "根分区调整完成,以下是新的分区布局:"
parted -s "$DISK" unit MB print free

# 检查文件系统一致性(非破坏性检查)
echo "正在检查文件系统一致性(非破坏性)..."
fsck -n "$ROOT_PARTITION" || {
    echo "警告:文件系统检查发现问题,建议手动运行 'e2fsck -f /dev/mmcblk0p5' 修复(需卸载或重启到单用户模式)。"
    echo "继续尝试在线扩展文件系统..."
}

# 执行文件系统扩展
echo "正在扩展根分区文件系统..."
resize2fs "$ROOT_PARTITION" || {
    echo "错误:文件系统扩展失败,请检查日志 $LOG_FILE。"
    echo "可能需要手动运行 'e2fsck -f /dev/mmcblk0p5' 和 'resize2fs /dev/mmcblk0p5'。"
    exit 1
}

# 显示扩展后的文件系统信息
echo "根分区文件系统扩展完成!以下是新的文件系统信息:"
df -h | grep "$ROOT_PARTITION"

# 检查交换文件相关工具和空间
echo "正在检查交换文件创建所需的工具和空间..."
if ! command -v mkswap >/dev/null 2>&1; then
    echo "错误:mkswap 未安装,请先安装 util-linux(例如:apt install util-linux)。"
    exit 1
fi

# 检查扩展后根文件系统可用空间是否足够创建 512MB 交换文件
FREE_SPACE_MB=$(df --block-size=1M "$MOUNT_POINT" | tail -n 1 | awk '{print $4}')
if [ -z "$FREE_SPACE_MB" ]; then
    echo "错误:无法获取扩展后根文件系统可用空间,请检查 df 命令输出。"
    exit 1
fi
if [ "$FREE_SPACE_MB" -lt "$SWAP_SIZE_MB" ]; then
    echo "错误:扩展后根文件系统可用空间 ($FREE_SPACE_MB MB) 小于所需的交换文件大小 ($SWAP_SIZE_MB MB)。"
    exit 1
fi
echo "扩展后根文件系统可用空间为 $FREE_SPACE_MB MB,足以创建 $SWAP_SIZE_MB MB 交换文件。"

# 创建交换文件
echo "正在创建 $SWAP_SIZE_MB MB 交换文件 ($SWAP_FILE)..."
if [ -f "$SWAP_FILE" ]; then
    echo "交换文件 $SWAP_FILE 已存在,跳过创建。"
else
    dd if=/dev/zero of="$SWAP_FILE" bs=1M count="$SWAP_SIZE_MB" status=progress || {
        echo "错误:创建交换文件失败,请检查日志 $LOG_FILE。"
        exit 1
    }
    chmod 600 "$SWAP_FILE" || {
        echo "错误:设置交换文件权限失败,请检查日志 $LOG_FILE。"
        exit 1
    }
    mkswap "$SWAP_FILE" || {
        echo "错误:格式化交换文件失败,请检查日志 $LOG_FILE。"
        exit 1
    }
fi

# 启用交换文件
echo "正在启用交换文件..."
swapon "$SWAP_FILE" || {
    echo "错误:启用交换文件失败,请检查日志 $LOG_FILE。"
    exit 1
}

# 添加交换文件到 fstab
echo "正在将交换文件添加到 /etc/fstab..."
if ! grep -q "$SWAP_FILE" /etc/fstab; then
    echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab
    echo "交换文件已添加到 /etc/fstab。"
else
    echo "交换文件已在 /etc/fstab 中,无需重复添加。"
fi

# 显示交换空间状态
echo "交换文件创建并启用完成!以下是交换空间信息:"
swapon --show

# 禁用脚本以防止下次启动重复执行
systemctl disable auto-expand-root.service
echo "脚本已完成并禁用自动执行,避免重复运行。"

echo "===== 根分区扩展与交换文件创建脚本执行完成: $(date) ====="
其中DISK="/dev/mmcblk0"
ROOT_PARTITION="${DISK}p5"是固定的,能不能改成通过findmnt -no SOURCE /来获取,其它功能不变,输出完整脚本代码,中文回答
0

评论 (0)

取消