|
|
本帖最后由 clxfire 于 2025-12-10 15:14 编辑
https://www.right.com.cn/forum/forum.php?mod=attachment&aid=NzY3NTQxfDBmOWEyMmYzfDE3ODc0ODI1OTd8MHw%3D
AI写的,注意备份硬盘数据后再使用!
#!/bin/bash
# armbian系统迁移到SSD脚本 (可双启动)
# 警告:此操作可能会修改目标磁盘分区,请先备份重要数据!
# 优先使用≈32GiB分区;额外分区按UUID自动写入fstab
set -euo pipefail
# 检查root权限
if [ "$(id -u)" -ne 0 ]; then
echo "错误:必须使用sudo或root权限运行此脚本"
exit 1
fi
# 智能设备检测
detect_devices() {
CURRENT_ROOT=$(findmnt / -o SOURCE -n)
CURRENT_UUID=$(findmnt / -o UUID -n)
if [[ $CURRENT_ROOT =~ "mmcblk" ]]; then
EMMC_DEVICE="/dev/$(lsblk -no NAME ${CURRENT_ROOT%p*})"
EMMC_ROOT_PART="$CURRENT_ROOT"
EMMC_ROOT_UUID="$CURRENT_UUID"
echo "检测到eMMC根分区: $EMMC_ROOT_PART (UUID: $EMMC_ROOT_UUID)"
else
echo "错误:当前系统不是从eMMC启动!"
exit 1
fi
# 获取候选SSD设备,排除 mmcblk 和 zram,并显示磁盘容量
mapfile -t SSD_CANDIDATES < <(
lsblk -d -n -o NAME,ROTA,SIZE |
awk '$2==0 && $1 !~ /^mmcblk/ && $1 !~ /^zram/ {print $1 ":" $3}'
)
if [ ${#SSD_CANDIDATES[@]} -eq 0 ]; then
echo "错误:未检测到SSD设备!"
exit 1
fi
local i=0
if [ ${#SSD_CANDIDATES[@]} -gt 1 ]; then
echo "检测到多个SSD设备:"
for i in "${!SSD_CANDIDATES[@]}"; do
echo "$((i + 1))). /dev/$(echo ${SSD_CANDIDATES[$i]} | cut -d: -f1) 容量: $(echo "${SSD_CANDIDATES[$i]}" | cut -d: -f2)"
done
while true; do
read -r -p "请选择要迁移的目标SSD编号: " choice
# 检查是否为正整数且在范围内
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "$i" ]; then
i=$((choice - 1))
break
else
echo "输入无效,请输入 1 到 $((i + 1)) 之间的数字。"
fi
done
fi
SIZE=$(echo "${SSD_CANDIDATES[$i]}" | cut -d: -f2)
TARGET_DISK="/dev/$(echo "${SSD_CANDIDATES[$i]}" | cut -d: -f1)"
echo "检测到SSD设备: $TARGET_DISK $SIZE"
MOUNT_DIR="/mnt/ssd_migrate"
if mountpoint -q "$MOUNT_DIR"; then
umount "$MOUNT_DIR"
fi
}
# 显示警告信息
show_warning() {
echo "========================================"
echo " 网心云 OEC armbian系统迁移SSD脚本"
echo "========================================"
echo "当前系统根分区: $EMMC_ROOT_PART (UUID: $EMMC_ROOT_UUID)"
echo "目标磁盘: $TARGET_DISK 容量: $SIZE"
echo "挂载目录: $MOUNT_DIR"
echo
echo "脚本行为:"
echo " - 优先查找目标磁盘上已有约32GiB的分区并格式化它作为主分区"
echo " - 若无此分区,则在尾部创建32GiB主分区并格式化"
echo " - 若空闲空间不足32GiB则退出,不会修改其他分区"
echo " - 自动为目标盘其它已有文件系统分区按UUID添加 fstab 挂载配置"
echo " - 如果仍有剩余空间,提示是否新建分区格式化添加 fstab 挂载配置"
echo "警告:此操作将格式化选定的分区,目标分区上的数据将被清除!"
echo "========================================"
read -p "确认继续操作? (输入大写的 'YES' 继续): " confirm
if [ "$confirm" != "YES" ]; then
echo "操作已取消"
exit 0
fi
}
# 将GiB转换为字节
gib_to_bytes() { echo $(($1 * 1024 * 1024 * 1024)); }
# 准备目标磁盘(优先从磁盘头部的空闲区创建 32GiB 分区;若无分区则从 1MiB 开始)
prepare_disk() {
echo -e "\n[1/8] 检查目标磁盘是否已有约32GiB分区..."
TARGET_SIZE_BYTES=$(gib_to_bytes 32)
LOWER_BOUND=$((TARGET_SIZE_BYTES - $(gib_to_bytes 1)))
UPPER_BOUND=$((TARGET_SIZE_BYTES + $(gib_to_bytes 1)))
FOUND_PART=""
while read -r name size type; do
if [ "$type" = "part" ]; then
if [ "$size" -ge "$LOWER_BOUND" ] && [ "$size" -le "$UPPER_BOUND" ]; then
FOUND_PART="$name"
break
fi
fi
done < <(lsblk -b -r -n -o NAME,SIZE,TYPE -p "$TARGET_DISK")
if [ -n "$FOUND_PART" ]; then
echo "找到符合大小的分区: $FOUND_PART (约32GiB),将格式化此分区作为主分区"
TARGET_PART="$FOUND_PART"
NEW_UUID=$(format_target_part "$TARGET_PART" "ROOTFS") || {
echo "格式化 $TARGET_PART 失败或被取消,脚本退出。"
exit 1
}
return 0
fi
echo "未找到约32GiB的现有分区,扫描空闲区以寻找从头部开始的连续32GiB空间..."
DISK_SIZE_BYTES=$(blockdev --getsize64 "$TARGET_DISK")
PART_SUM=0
while read -r name size type; do
if [ "$type" = "part" ]; then
PART_SUM=$((PART_SUM + size))
fi
done < <(lsblk -b -r -n -o NAME,SIZE,TYPE -p "$TARGET_DISK")
FREE_BYTES=$((DISK_SIZE_BYTES - PART_SUM))
echo "磁盘总大小: $DISK_SIZE_BYTES 字节, 已分区总和: $PART_SUM 字节, 估算空闲: $FREE_BYTES 字节"
if [ "$FREE_BYTES" -lt "$TARGET_SIZE_BYTES" ]; then
echo "错误:目标磁盘空闲空间不足 32GiB,无法创建分区。脚本退出。"
exit 1
fi
# 若无分区表则创建 GPT(避免 mkpart 失败)
parted_output=$(parted -s "$TARGET_DISK" print 2>/dev/null || true)
if echo "$parted_output" | grep -qi "Partition Table: unknown"; then
echo "检测到无分区表,正在为 $TARGET_DISK 创建 GPT 分区表(mklabel gpt)..."
parted -s "$TARGET_DISK" mklabel gpt
partprobe "$TARGET_DISK"
sleep 1
fi
# 以 MiB 为单位
size_mib=$((32 * 1024))
disk_size_mib=$((DISK_SIZE_BYTES / 1024 / 1024))
# 解析 parted 的 free 段(兼容多数输出),收集 Start/End
mapfile -t free_ranges < <(parted -s "$TARGET_DISK" unit MiB print free 2>/dev/null |
awk '/[Ff]ree/ && /MiB/ {
start=$2; end=$3;
gsub("MiB","",start); gsub("MiB","",end);
if (start+0==start && end+0==end) {
printf "%d %d\n", int(start), int(end)
}
}')
chosen_start=0
chosen_end=0
# 特殊情况:磁盘上没有任何分区(PART_SUM==0 或 free_ranges 为空)
if [ "$PART_SUM" -eq 0 ] || [ "${#free_ranges[@]}" -eq 0 ]; then
# 从头部开始:保留前 1MiB(对齐),起点设为 1MiB
start_mib=1
end_mib=$((start_mib + size_mib))
# 校验是否越界
if [ "$end_mib" -gt "$disk_size_mib" ]; then
echo "错误:磁盘太小,无法从头部创建 32GiB 分区"
exit 1
fi
chosen_start=$start_mib
chosen_end=$end_mib
echo "磁盘无分区,选择从头部创建分区: ${chosen_start}MiB - ${chosen_end}MiB (约32GiB)"
else
# 在 free_ranges 中选择最早出现且长度 >= size_mib 的区间(从头部优先)
for fr in "${free_ranges[@]:-}"; do
start_mib=$(echo "$fr" | awk '{print $1}')
end_mib=$(echo "$fr" | awk '{print $2}')
seg_size=$((end_mib - start_mib))
if [ "$seg_size" -ge "$size_mib" ]; then
chosen_start=$start_mib
chosen_end=$((chosen_start + size_mib))
echo "找到从头部优先的空闲区: ${start_mib}MiB - ${end_mib}MiB (大小 ${seg_size}MiB),将在其起点创建 ${size_mib}MiB 分区"
break
fi
done
if [ "$chosen_start" -eq 0 ]; then
echo "错误:未在磁盘任意空闲区(从头部开始扫描)找到连续 32GiB 空间。脚本不会在尾部回退创建,已退出。"
exit 1
fi
fi
# 创建分区
parted -s "$TARGET_DISK" mkpart primary ext4 "${chosen_start}MiB" "${chosen_end}MiB"
partprobe "$TARGET_DISK"
sleep 2
# 识别新分区(重试以等待内核识别)
local NEW_PART=""
for attempt in 1 2 3 4 5; do
while read -r name size type; do
if [ "$type" = "part" ]; then
if [ "$size" -ge "$LOWER_BOUND" ] && [ "$size" -le "$UPPER_BOUND" ]; then
NEW_PART="$name"
break 2
fi
fi
done < <(lsblk -b -r -n -o NAME,SIZE,TYPE -p "$TARGET_DISK")
sleep 1
partprobe "$TARGET_DISK" 2>/dev/null || true
done
if [ -z "$NEW_PART" ]; then
echo "错误:创建分区后未能找到对应的32GiB分区"
exit 1
fi
TARGET_PART="$NEW_PART"
echo "创建并识别到新分区: $TARGET_PART"
NEW_UUID=$(format_target_part "$TARGET_PART" "ROOTFS") || {
echo "格式化 $TARGET_PART 失败或被取消,脚本退出。"
exit 1
}
}
# 格式化指定分区并返回新 UUID
# 用法: NEW_UUID=$(format_target_part "/dev/sda2" "ROOTFS") || handle_error
format_target_part() {
local part="$1"
local label="${2:-ROOTFS}"
if [ -z "$part" ]; then
echo "format_target_part: 缺少分区参数" >&2
return 1
fi
if [ ! -b "$part" ]; then
echo "format_target_part: 未找到设备 $part" >&2
return 1
fi
# 显示信息并确认(提示信息走 stderr)
local size_hr
size_hr=$(lsblk -no SIZE -p "$part" 2>/dev/null || true)
echo -e "\n准备格式化: $part" >&2
echo "大小: ${size_hr:-未知} 标签: $label" >&2
echo "警告:此操作将清除 $part 上的所有数据!" >&2
read -r -p "确认格式化 (输入大写 YES 或再次输入分区路径以确认): " confirm
if [ "$confirm" != "YES" ] && [ "$confirm" != "$part" ]; then
echo "format_target_part: 用户取消格式化" >&2
return 2
fi
# 执行格式化
if ! mkfs.ext4 -F -L "$label" "$part" >/dev/null 2>&1; then
echo "format_target_part: mkfs.ext4 失败 $part" >&2
return 1
fi
sync
# 等待并读取 UUID
local retries=6
local new_uuid=""
while [ $retries -gt 0 ]; do
new_uuid=$(blkid -s UUID -o value "$part" 2>/dev/null || true)
if [ -n "$new_uuid" ]; then
# 仅输出 UUID 到 stdout(便于调用方捕获)
printf "%s" "$new_uuid"
return 0
fi
sleep 1
retries=$((retries - 1))
partprobe "$(dirname "$part")" 2>/dev/null || true
udevadm settle 2>/dev/null || true
done
echo "format_target_part: 无法获取新分区 UUID" >&2
return 1
}
# 复制系统文件
copy_system() {
echo -e "\n[4/8] 挂载目标分区..."
mkdir -p "$MOUNT_DIR"
mount "$TARGET_PART" "$MOUNT_DIR"
echo -e "\n[5/8] 复制系统文件(可能需要较长时间)..."
rsync -aAXv --progress \
--exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} \
/ "$MOUNT_DIR"
echo -e "\n[6/8] 处理boot目录..."
if [ -d "$MOUNT_DIR/boot" ]; then
rsync -aAXv /boot/ "$MOUNT_DIR/boot/"
else
mkdir -p "$MOUNT_DIR/boot"
rsync -aAXv /boot/ "$MOUNT_DIR/boot/"
fi
}
# 自动为目标盘剩余已有分区添加 fstab;若无分区则使用全部剩余空间创建新分区并格式化
setup_extra_mounts() {
echo -e "\n[7/8] 配置剩余分区的自动挂载 (按分区名),若无分区则使用全部剩余空间创建新分区并格式化..."
mkdir -p "$MOUNT_DIR/mnt/storage"
# 列出目标磁盘的分区(绝对路径),排除主系统分区
mapfile -t parts < <(lsblk -b -r -n -o NAME,TYPE -p "$TARGET_DISK" | awk '$2=="part" {print $1}')
filtered_parts=()
for p in "${parts[@]:-}"; do
if [ -n "${TARGET_PART:-}" ] && [ "$p" = "$TARGET_PART" ]; then
continue
fi
filtered_parts+=("$p")
done
# helper: 解析 parted free 段并选择第一个有效 free 段(返回 start end MiB 或空)
find_free_range() {
local disk="$1"
local disk_size_bytes
disk_size_bytes=$(blockdev --getsize64 "$disk")
local disk_size_mib=$((disk_size_bytes / 1024 / 1024))
mapfile -t free_ranges < <(parted -s "$disk" unit MiB print free 2>/dev/null |
grep -i "free" | sed -E 's/,//g' | awk '{
n=0;
for(i=1;i<=NF;i++){
if($i ~ /[0-9]+(\.[0-9]+)?MiB/){
gsub("MiB","",$i);
printf "%s ", $i;
n++;
if(n==2) break;
}
}
if(n==2) print "";
}')
for fr in "${free_ranges[@]:-}"; do
start_mib=$(echo "$fr" | awk '{print $1}')
end_mib=$(echo "$fr" | awk '{print $2}')
if ! [[ "$start_mib" =~ ^[0-9]+([.][0-9]+)?$ ]] || ! [[ "$end_mib" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
continue
fi
start_mib=${start_mib%.*}
end_mib=${end_mib%.*}
if [ "$start_mib" -gt "$end_mib" ]; then
tmp=$start_mib
start_mib=$end_mib
end_mib=$tmp
fi
if [ "$end_mib" -le "$start_mib" ]; then
continue
fi
if [ "$start_mib" -lt 1 ]; then
start_mib=1
fi
if [ "$end_mib" -le "$start_mib" ]; then
continue
fi
# 返回第一个有效段
printf "%s %s" "$start_mib" "$end_mib"
return 0
done
# 回退:从 1MiB 到磁盘尾部
if [ "$disk_size_mib" -gt 1 ]; then
printf "1 %s" "$disk_size_mib"
return 0
fi
return 1
}
# helper: 创建分区、格式化并写入 fstab(参数: disk start_mib end_mib)
create_and_register_partition() {
local disk="$1"
local start_mib="$2"
local end_mib="$3"
echo "将在 ${disk} 上创建新分区: ${start_mib}MiB - ${end_mib}MiB"
read -r -p "确认创建新分区 (输入大写 YES 继续): " confirm
if [ "$confirm" != "YES" ]; then
echo "format_target_part: 用户取消格式化" >&2
return 2
fi
parted -s "$disk" mkpart primary ext4 "${start_mib}MiB" "${end_mib}MiB"
partprobe "$disk" 2>/dev/null || true
udevadm settle 2>/dev/null || true
sleep 2
local segment_bytes=$(((end_mib - start_mib) * 1024 * 1024))
local NEW_PART=""
for attempt in 1 2 3 4 5; do
lower=$((segment_bytes - 1024 * 1024))
upper=$((segment_bytes + 1024 * 1024))
while read -r name size type; do
if [ "$type" = "part" ]; then
if [ "$size" -ge "$lower" ] && [ "$size" -le "$upper" ]; then
NEW_PART="$name"
break 2
fi
fi
done < <(lsblk -b -r -n -o NAME,SIZE,TYPE -p "$disk")
partprobe "$disk" 2>/dev/null || true
udevadm settle 2>/dev/null || true
sleep 1
done
if [ -z "$NEW_PART" ]; then
echo "警告:创建分区后未能识别新分区,跳过格式化与挂载。"
echo "parted free 输出:"
parted -s "$disk" unit MiB print free 2>/dev/null || true
echo "lsblk 输出:"
lsblk -b -o NAME,SIZE,TYPE -p "$disk"
return 1
fi
echo "识别到新分区: $NEW_PART,准备格式化(将触发确认)"
# 假设 format_target_part 函数存在并返回 UUID(与你原逻辑一致)
local PART_UUID PART_FSTYPE
PART_UUID=$(format_target_part "$NEW_PART" "DATA") || {
echo "格式化 $NEW_PART 失败或被取消,脚本退出。"
exit 1
}
PART_UUID=$(blkid -s UUID -o value "$NEW_PART" || true)
PART_FSTYPE=$(blkid -s TYPE -o value "$NEW_PART" || true)
if [ -z "$PART_UUID" ] || [ -z "$PART_FSTYPE" ]; then
echo "格式化后无法获取分区 UUID 或 文件系统类型,跳过写入 fstab。"
return 1
fi
local ident_name mount_point opts fstab_file
ident_name="$(basename "$NEW_PART")"
mount_point="/mnt/storage/$ident_name"
mkdir -p "$MOUNT_DIR$mount_point"
opts="nofail,x-systemd.automount,x-systemd.mount-timeout=10s"
case "$PART_FSTYPE" in
ext4 | ext3 | ext2) opts="defaults,$opts" ;;
xfs) opts="noatime,$opts" ;;
btrfs) opts="ssd,noatime,compress-force=zstd:3,$opts" ;;
f2fs) opts="noatime,compress_algorithm=lz4,$opts" ;;
ntfs | exfat | vfat) opts="uid=0,gid=0,umask=0022,$opts" ;;
*) opts="defaults,$opts" ;;
esac
fstab_file="$MOUNT_DIR/etc/fstab"
if grep -q "UUID=$PART_UUID" "$fstab_file"; then
echo "fstab 已存在 UUID=$PART_UUID 的条目,跳过添加"
else
echo "添加 fstab: UUID=$PART_UUID $mount_point $PART_FSTYPE $opts 0 2"
printf "UUID=%s %s %s %s 0 2\n" "$PART_UUID" "$mount_point" "$PART_FSTYPE" "$opts" >>"$fstab_file"
fi
return 0
}
# 如果没有剩余分区,检查磁盘是否还有未使用空间(原有逻辑)
if [ "${#filtered_parts[@]}" -eq 0 ]; then
echo "未检测到除主分区外的其他分区,检查是否存在未使用空间以创建新分区..."
DISK_SIZE_BYTES=$(blockdev --getsize64 "$TARGET_DISK")
PART_SUM=0
while read -r name size type; do
if [ "$type" = "part" ]; then
PART_SUM=$((PART_SUM + size))
fi
done < <(lsblk -b -r -n -o NAME,SIZE,TYPE -p "$TARGET_DISK")
FREE_BYTES=$((DISK_SIZE_BYTES - PART_SUM))
echo "磁盘总大小: $DISK_SIZE_BYTES 字节, 已分区总和: $PART_SUM 字节, 估算空闲: $FREE_BYTES 字节"
MIN_CREATE_BYTES=$((1 * 1024 * 1024))
if [ "$FREE_BYTES" -lt "$MIN_CREATE_BYTES" ]; then
echo "未检测到足够的未使用空间用于创建新分区,跳过创建。"
else
parted_output=$(parted -s "$TARGET_DISK" print 2>/dev/null || true)
if echo "$parted_output" | grep -qi "Partition Table: unknown"; then
echo "检测到无分区表,正在为 $TARGET_DISK 创建 GPT 分区表(mklabel gpt)..."
parted -s "$TARGET_DISK" mklabel gpt
partprobe "$TARGET_DISK"
sleep 1
fi
if free_pair=$(find_free_range "$TARGET_DISK"); then
start_mib=$(echo "$free_pair" | awk '{print $1}')
end_mib=$(echo "$free_pair" | awk '{print $2}')
echo "选择空闲区: ${start_mib}MiB - ${end_mib}MiB (使用全部剩余空间)"
create_and_register_partition "$TARGET_DISK" "$start_mib" "$end_mib" || true
else
echo "无法确定可用空闲区,跳过创建。"
fi
fi
else
# 有剩余分区,按原逻辑为每个分区添加 fstab
for name in "${filtered_parts[@]}"; do
PART_UUID=$(blkid -s UUID -o value "$name" || true)
PART_FSTYPE=$(blkid -s TYPE -o value "$name" || true)
if [ -z "$PART_FSTYPE" ] || [ -z "$PART_UUID" ]; then
echo "跳过不可挂载分区: $name (TYPE='$PART_FSTYPE', UUID='$PART_UUID')"
continue
fi
ident_name="$(basename "$name")"
mount_point="/mnt/storage/$ident_name"
mkdir -p "$MOUNT_DIR$mount_point"
fstab_file="$MOUNT_DIR/etc/fstab"
if grep -q "UUID=$PART_UUID" "$fstab_file"; then
echo "fstab 已存在 UUID=$PART_UUID 的条目,跳过"
continue
fi
opts="nofail,x-systemd.automount,x-systemd.mount-timeout=10s"
case "$PART_FSTYPE" in
ext4 | ext3 | ext2) opts="defaults,$opts" ;;
xfs) opts="noatime,$opts" ;;
btrfs) opts="ssd,noatime,compress-force=zstd:3,$opts" ;;
f2fs) opts="noatime,compress_algorithm=lz4,$opts" ;;
ntfs | exfat | vfat) opts="uid=0,gid=0,umask=0022,$opts" ;;
*) opts="defaults,$opts" ;;
esac
echo "添加 fstab: UUID=$PART_UUID $mount_point $PART_FSTYPE $opts 0 2"
printf "UUID=%s %s %s %s 0 2\n" "$PART_UUID" "$mount_point" "$PART_FSTYPE" "$opts" >>"$fstab_file"
done
# 处理:已有分区但仍有未分配空间时,尝试创建一个新分区并格式化(与上面逻辑一致)
DISK_SIZE_BYTES=$(blockdev --getsize64 "$TARGET_DISK")
PART_SUM=0
while read -r name size type; do
if [ "$type" = "part" ]; then
PART_SUM=$((PART_SUM + size))
fi
done < <(lsblk -b -r -n -o NAME,SIZE,TYPE -p "$TARGET_DISK")
FREE_BYTES=$((DISK_SIZE_BYTES - PART_SUM))
MIN_CREATE_BYTES=$((1 * 1024 * 1024))
if [ "$FREE_BYTES" -ge "$MIN_CREATE_BYTES" ]; then
echo "检测到磁盘仍有未分配空间,尝试使用全部剩余空间创建新分区..."
parted_output=$(parted -s "$TARGET_DISK" print 2>/dev/null || true)
if echo "$parted_output" | grep -qi "Partition Table: unknown"; then
echo "检测到无分区表,正在为 $TARGET_DISK 创建 GPT 分区表(mklabel gpt)..."
parted -s "$TARGET_DISK" mklabel gpt
partprobe "$TARGET_DISK"
sleep 1
fi
if free_pair=$(find_free_range "$TARGET_DISK"); then
start_mib=$(echo "$free_pair" | awk '{print $1}')
end_mib=$(echo "$free_pair" | awk '{print $2}')
echo "选择空闲区: ${start_mib}MiB - ${end_mib}MiB (使用全部剩余空间)"
create_and_register_partition "$TARGET_DISK" "$start_mib" "$end_mib" || true
else
echo "未解析到可用 free 段,跳过创建。"
fi
else
echo "未检测到足够的未使用空间用于创建新分区,跳过创建。"
fi
fi
echo "剩余分区的 fstab 挂载配置完成(按分区名)。"
}
# 更新配置文件(根fs和引导)
update_rootfs_uuid() {
echo -e "\n[8/8] 更新SSD rootfs分区UUID..."
if mountpoint -q "$MOUNT_DIR"; then
echo -e "取消挂载 $TARGET_PART"
umount "$MOUNT_DIR"
sleep 3
fi
echo -e "将$TARGET_PART UUID $NEW_UUID 改为EMMC UUID $EMMC_ROOT_UUID"
e2fsck -f -y "$TARGET_PART"
tune2fs -U "$EMMC_ROOT_UUID" "$TARGET_PART"
}
# 一键删除所有分区(危险操作)
wipe_all_partitions() {
echo "========================================"
echo "警告:此操作将删除 $TARGET_DISK 上的所有分区!"
echo "所有数据将不可恢复,请确认已备份!"
echo "========================================"
read -p "确认删除所有分区? (输入大写 'WIPE' 继续): " confirm
if [ "$confirm" != "WIPE" ]; then
echo "操作已取消"
return 1
fi
# 使用 parted 清空分区表
echo "正在清空分区表..."
parted -s "$TARGET_DISK" mklabel gpt
partprobe "$TARGET_DISK"
echo "已删除所有分区,磁盘现在为空。"
}
# 一键删除所有分区(危险操作)
wipe_all_partitions() {
# 红色提醒
echo -e "\033[1;31m========================================\033[0m"
echo -e "\033[1;31m警告:此操作将删除 $TARGET_DISK 上的所有分区!\033[0m"
echo -e "\033[1;31m所有数据将不可恢复,请确认已备份!\033[0m"
echo -e "\033[1;31m========================================\033[0m"
read -p "确认删除所有分区? (输入大写 'WIPE' 继续): " confirm
if [ "$confirm" != "WIPE" ]; then
echo "操作已取消"
return 1
fi
# 使用 parted 清空分区表
echo "正在清空分区表..."
parted -s "$TARGET_DISK" mklabel gpt
partprobe "$TARGET_DISK"
echo "已删除所有分区,磁盘现在为空。"
}
# 清理和完成
cleanup() {
echo -e "\n清理环境..."
if mountpoint -q "$MOUNT_DIR"; then
umount "$MOUNT_DIR"
fi
rmdir "$MOUNT_DIR" 2>/dev/null || true
echo "========================================"
echo "系统迁移完成!"
echo "1. 插入SSD时:从SSD启动 "
echo "2. 无SSD时:从eMMC启动"
echo
echo "操作指南:"
echo "1. 关闭计算机: shutdown -h now"
echo "2. 确保SSD已正确连接"
echo "3. 首次启动后运行: sudo update-initramfs -u"
echo "========================================"
}
# 菜单函数
show_menu() {
echo "========================================"
echo "请选择操作模式:"
echo "1) 正常迁移系统到SSD"
echo "2) 一键删除SSD内所有分区 (慎用,只是用作清除SSD磁盘数据方便迁移)"
echo "3) 退出脚本"
echo "========================================"
read -p "输入选项编号: " mode
case "$mode" in
1)
detect_devices
clear
show_warning
prepare_disk
copy_system
setup_extra_mounts
update_rootfs_uuid
cleanup
# 完成迁移后退出脚本
exit 0
;;
2)
clear
detect_devices
wipe_all_partitions
# 删除完成后再次调用菜单函数
show_menu
;;
3)
echo "已退出脚本。"
exit 0
;;
*)
echo "无效选项,请重新输入。"
show_menu
;;
esac
}
# 主入口
show_menu
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|