UbuntuやFedora、CachyOSなど、さまざまなディストリビューションがありますが、どれも完成度は高くなってきていますね。
Ubuntu、Fedora、CachyOSを触った感想
触った感じで個人的な印象ですが、Windowsなどに例えるとそれぞれ次のようなイメージです。
Ubuntu・・・MacOS
Fedora・・・Windows
CachyOS・・Linux
とにかく完成度が高く、インストール直後からすぐ使えるのはUbuntuですね。デザインも統一されておりシンプルで分かりやすくなっています。ただ、カスタマイズ要素は低めになっており、安定度重視で、道具として使うイメージです。
CachyOSはキビキビ動くんですが、ある程度は設定が必要になります。ただ自由度は高いですね。またゲーム用途ならCachyOSが一番でしょう。
Fedoraはそれらの中間といった雰囲気です。
普段Windowsを使っている人がLinuxを試してみるなら、Ubuntuが一番良いと思います。
ファイルシステムについて
Ubuntuは安定度重視でファイルシステムはext4になっていますが、FedoraやCachyOSのデフォルトはBtrfsを採用しています。Btrfsの最大の魅力はスナップショット機能。デスクトップ用途で使う場合は、不具合時でもすぐに戻せるのは安心感があります。
こちらでもTimeshiftについて触れましたが、Timeshiftの魅力を最大限に活かすならBtrfsパーティションにしたいところです。しかし、Canonicalのエンジニアはセキュリティ強化を目的として、Ubuntu 26.10において、署名付きGRUBブートローダーからBtrfs、ZFS、XFSなどのファイルシステムやLVM、LUKS暗号化のサポートを削除する計画を提案しているそうですし、あまりBtrfsパーティションに積極的ではなさそうです。
そこで、この変更が実施された場合でも問題なく動かすように、/bootを別パーティションにしてBtrfsを導入してみます。
手動でパーティションを分割
Ubuntuインストール時に、パーティションを手動作成します。

先頭はブートローダーを格納するパーティションとして1GB程度のFAT32パーティションを作成。
2つ目はカーネルを格納するExt4パーティションを作成。容量は1GB〜2GB程度で/bootにマウントします。
そして残りをBtrfsパーティションにして/にマウントします。
なお、一番最後にUbuntuのISOイメージを置いておくといざという時に便利なので、必要な場合はその部分も確保しておきます。ここではExt4パーティションで/isoにマウントしています。

ISOパーティションを用意した場合はGRUBメニューに追加
ISOパーティションを作成した場合は、Ubuntuのインストール後に、GRUBメニューに項目を追加します。
まず/isoの所有者変更と書き込み権限を付与します。
sudo chown $USER:$USER /iso
chmod u+rwx /iso
続いてスクリプトを保存して実行します。スクリプトの保存先を/isoにしておけば、このISOブートを利用してクリーンインストールした時など、再度GRUBメニューに項目を追加したい場合に便利です。
cd /iso
nano isoboot-grub.sh
sudo bash isoboot-grub.sh
#!/usr/bin/env bash
# =============================================================================
# isoboot-grub.sh
# ISOブート用パーティション確認 → GRUB エントリ追加スクリプト
# 前提:ISOファイル入りのext4パーティションが既に存在すること
# =============================================================================
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
info() { echo -e "${CYAN}[INFO]${RESET} $*"; }
success() { echo -e "${GREEN}[OK]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
error() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
die() { error "$*"; exit 1; }
hr() { echo -e "${CYAN}$(printf '=%.0s' {1..70})${RESET}"; }
confirm() {
local ans
while true; do
echo -en "${YELLOW}[確認]${RESET} $1 [y/N]: "
read -r ans
case "$ans" in
[yY]*) return 0 ;;
[nN]*|"") return 1 ;;
*) echo " y または n を入力してください。" ;;
esac
done
}
# -----------------------------------------------------------------------------
check_root() {
[[ $EUID -eq 0 ]] || die "sudo で実行してください。\n 例: sudo bash $0"
}
check_deps() {
local missing=()
for cmd in lsblk blkid mount umount file grub-mkconfig update-grub; do
command -v "$cmd" &>/dev/null || missing+=("$cmd")
done
[[ ${#missing[@]} -eq 0 ]] || die "コマンドが見つかりません: ${missing[*]}"
}
# -----------------------------------------------------------------------------
# ステップ1: ISOが入ったパーティションを選択
# -----------------------------------------------------------------------------
select_partition() {
hr
echo -e "${BOLD}【ステップ 1/3】ISO パーティションの選択${RESET}"
hr
echo ""
info "現在のパーティション一覧:"
echo ""
lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINTS | grep -v loop
echo ""
while true; do
echo -en "${BOLD}ISOが入ったパーティションを入力${RESET} (例: vda3, sda4, nvme0n1p3): /dev/"
read -r part_name
PART_DEV="/dev/${part_name}"
if [[ ! -b "$PART_DEV" ]]; then
error "${PART_DEV} はブロックデバイスではありません。再入力してください。"
continue
fi
local fstype
fstype=$(lsblk -no FSTYPE "$PART_DEV" 2>/dev/null || true)
if [[ "$fstype" != "ext4" ]]; then
warn "${PART_DEV} のファイルシステムは ${fstype:-不明} です(ext4 を想定)。"
confirm "このまま続けますか?" || continue
fi
echo ""
info "${PART_DEV} の情報:"
lsblk -o NAME,SIZE,FSTYPE,LABEL,UUID,MOUNTPOINTS "$PART_DEV" 2>/dev/null || true
echo ""
confirm "${PART_DEV} を使用しますか?" && break
done
success "対象パーティション: ${PART_DEV}"
# UUID取得(デバイス名非依存・VM/実機共通)
PART_UUID=$(blkid -s UUID -o value "$PART_DEV")
if [[ -z "$PART_UUID" ]]; then
die "UUIDを取得できませんでした: ${PART_DEV}"
fi
success "UUID: ${PART_UUID}"
}
# -----------------------------------------------------------------------------
# ステップ2: ISOファイルの確認と起動パス検出
# -----------------------------------------------------------------------------
inspect_isos() {
hr
echo -e "${BOLD}【ステップ 2/3】ISO ファイルの確認${RESET}"
hr
echo ""
MOUNT_POINT="/mnt/isoboot_grub_$$"
mkdir -p "$MOUNT_POINT"
mount "$PART_DEV" "$MOUNT_POINT"
info "${PART_DEV} を ${MOUNT_POINT} にマウントしました"
echo ""
# ISOファイルを列挙
mapfile -t iso_candidates < <(find "$MOUNT_POINT" -maxdepth 2 -name "*.iso" 2>/dev/null)
if [[ ${#iso_candidates[@]} -eq 0 ]]; then
umount "$MOUNT_POINT"; rmdir "$MOUNT_POINT"
die "ISOファイルが見つかりませんでした。パーティションにISOを配置してから再実行してください。"
fi
info "見つかったISOファイル:"
for i in "${!iso_candidates[@]}"; do
local size
size=$(du -sh "${iso_candidates[$i]}" 2>/dev/null | cut -f1)
echo " [$((i+1))] ${iso_candidates[$i]##"$MOUNT_POINT"} (${size})"
done
echo ""
ISO_ENTRIES=() # "iso_path:vmlinuz:initrd:boot_type" の配列
for iso_full in "${iso_candidates[@]}"; do
local iso_rel="${iso_full##"$MOUNT_POINT"}"
local iso_name
iso_name=$(basename "$iso_full")
echo ""
info "--- ${iso_name} を検査中 ---"
if confirm "${iso_name} をGRUBメニューに追加しますか?"; then
local paths
paths=$(detect_boot_paths "$iso_full")
local vmlinuz="${paths%%:*}"
local rest="${paths#*:}"
local initrd="${rest%%:*}"
local boot_type="${rest##*:}"
if [[ "$vmlinuz" == "UNKNOWN" ]]; then
warn "カーネルパスを自動検出できませんでした。手動入力してください。"
echo -en " vmlinuz のパス (例: /casper/vmlinuz): "
read -r vmlinuz
echo -en " initrd のパス (例: /casper/initrd): "
read -r initrd
boot_type="custom"
else
success "カーネル : ${vmlinuz}"
success "initrd : ${initrd}"
success "起動方式 : ${boot_type}"
fi
ISO_ENTRIES+=("${iso_rel}:${vmlinuz}:${initrd}:${boot_type}")
else
info "スキップ: ${iso_name}"
fi
done
umount "$MOUNT_POINT"
rmdir "$MOUNT_POINT"
success "アンマウント完了"
if [[ ${#ISO_ENTRIES[@]} -eq 0 ]]; then
die "追加するエントリがありません。終了します。"
fi
}
# ISOをループマウントして起動パスを自動検出
detect_boot_paths() {
local iso_path="$1"
local tmp="/mnt/iso_inspect_$$"
mkdir -p "$tmp"
if ! mount -o loop,ro "$iso_path" "$tmp" 2>/dev/null; then
echo "UNKNOWN:UNKNOWN:custom"
return
fi
local vmlinuz="" initrd="" boot_type=""
if [[ -f "$tmp/casper/vmlinuz" ]]; then vmlinuz="/casper/vmlinuz"; initrd="/casper/initrd"; boot_type="casper"
elif [[ -f "$tmp/casper/vmlinuz.efi" ]]; then vmlinuz="/casper/vmlinuz.efi"; initrd="/casper/initrd.lz"; boot_type="casper"
elif [[ -f "$tmp/live/vmlinuz" ]]; then vmlinuz="/live/vmlinuz"; initrd="/live/initrd.img"; boot_type="live"
elif [[ -f "$tmp/live/vmlinuz.efi" ]]; then vmlinuz="/live/vmlinuz.efi"; initrd="/live/initrd.img"; boot_type="live"
else
# フォールバック:vmlinuz を再帰検索
local found
found=$(find "$tmp" -name "vmlinuz*" | head -1 || true)
if [[ -n "$found" ]]; then
vmlinuz="${found##"$tmp"}"
local dir
dir=$(dirname "$found")
initrd=$(find "$dir" -name "initrd*" | head -1 || true)
initrd="${initrd##"$tmp"}"
boot_type="custom"
else
vmlinuz="UNKNOWN"; initrd="UNKNOWN"; boot_type="custom"
fi
fi
umount "$tmp"; rmdir "$tmp"
echo "${vmlinuz}:${initrd}:${boot_type}"
}
# -----------------------------------------------------------------------------
# ステップ3: GRUBエントリ追加
# -----------------------------------------------------------------------------
add_grub_entries() {
hr
echo -e "${BOLD}【ステップ 3/3】GRUB エントリの追加${RESET}"
hr
echo ""
local custom_file="/etc/grub.d/40_custom"
cp "$custom_file" "${custom_file}.bak.$(date +%Y%m%d_%H%M%S)"
info "40_custom をバックアップしました"
echo ""
for entry in "${ISO_ENTRIES[@]}"; do
local iso_rel vmlinuz initrd boot_type menu_label
IFS=':' read -r iso_rel vmlinuz initrd boot_type <<< "$entry"
menu_label=$(basename "$iso_rel" .iso)
local params=""
case "$boot_type" in
casper) params="boot=casper iso-scan/filename=\$isofile quiet splash ---" ;;
live) params="boot=live iso-scan/filename=\$isofile quiet splash" ;;
*) params="iso-scan/filename=\$isofile quiet splash" ;;
esac
local grub_entry
grub_entry=$(cat <<EOF
menuentry "${menu_label} (ISO Loop Boot)" {
insmod part_gpt
insmod ext2
insmod loopback
insmod iso9660
search --no-floppy --fs-uuid --set=isodev ${PART_UUID}
set isofile="${iso_rel}"
loopback loop (\$isodev)\$isofile
linux (loop)${vmlinuz} ${params}
initrd (loop)${initrd}
}
EOF
)
echo -e "${CYAN}追加予定エントリ:${RESET}"
echo "$grub_entry"
echo ""
if confirm "このエントリを追加しますか?"; then
echo "$grub_entry" >> "$custom_file"
success "追加しました: ${menu_label}"
else
warn "スキップ: ${menu_label}"
fi
done
echo ""
info "GRUB を更新中..."
if update-grub 2>&1; then
success "update-grub 完了"
else
warn "update-grub でエラーが発生しました。手動で確認してください:"
warn " sudo update-grub"
fi
}
# -----------------------------------------------------------------------------
# 完了サマリー
# -----------------------------------------------------------------------------
print_summary() {
hr
echo -e "${BOLD}${GREEN}【完了】セットアップサマリー${RESET}"
hr
echo ""
echo -e " 対象パーティション : ${BOLD}${PART_DEV}${RESET}"
echo -e " パーティションUUID : ${BOLD}${PART_UUID}${RESET}"
echo -e " 追加エントリ数 : ${BOLD}${#ISO_ENTRIES[@]}${RESET}"
echo ""
echo -e "${YELLOW}【次のステップ】${RESET}"
echo " 1. 再起動して GRUB メニューに新しいエントリが表示されることを確認"
echo " 2. 起動に失敗した場合は /etc/grub.d/40_custom を確認し"
echo " カーネルパスを修正後 sudo update-grub を再実行"
echo ""
warn "バックアップ: /etc/grub.d/40_custom.bak.* に保存済み"
hr
}
# -----------------------------------------------------------------------------
main() {
clear
hr
echo -e "${BOLD} isoboot-grub.sh — ISO ブート GRUB エントリ 追加スクリプト${RESET}"
echo -e " 前提: ISOファイル入りのext4パーティションが既に存在すること"
hr
echo ""
check_root
check_deps
select_partition
inspect_isos
add_grub_entries
print_summary
}
main "$@"
サブボリューム移行用スクリプト作成
Ubuntu24.04以降では、インストール時にBtrfsを選択しても自動で@、@homeを作成しないようになっています。ひとまずマウント状況を確認します。
mount | grep btrfs
下記のように、/や/homeのままとなっているはずです。
/dev/vda3 on / type btrfs (rw,relatime,discard=async,space_cache=v2,subvolid=5,subvol=/) # subvol=/@のようになっていない。
サブボリュームへ移行するスクリプトをホームフォルダ内に保存しておきます。
もし、/isoを作成しているなら、このスクリプトも/isoフォルダに保存しておいたほうが便利です。
cd /iso
nano btrfs_migrate.sh
#!/bin/bash
# ============================================================
# Btrfs サブボリューム移行スクリプト(統合版)
# 実行環境: ライブUSB環境のターミナル
# 構成A: EFI + btrfs の2パーティション構成
# 構成B: EFI + ext4(/boot) + btrfs の3パーティション構成
# EFI(UEFI)/ BIOS(Legacy)両対応
# 使い方 : sudo bash btrfs_migrate.sh
# ============================================================
set -euo pipefail
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }
step() { echo -e "\n${CYAN}=== $* ===${NC}"; }
[[ $EUID -ne 0 ]] && error "sudo で実行してください"
# ============================================================
# 環境検出
# ============================================================
step "環境を自動検出"
if [[ -d /sys/firmware/efi ]]; then
BOOT_MODE="EFI"
else
BOOT_MODE="BIOS"
fi
info "起動モード: $BOOT_MODE"
# Btrfsパーティション検出
BTRFS_PART=$(lsblk -lnpo NAME,FSTYPE | awk '$2=="btrfs"{print $1}' | head -1)
[[ -n "$BTRFS_PART" ]] || error "Btrfsパーティションが見つかりませんでした"
# ディスク本体
DISK=$(lsblk -lnpo PKNAME "$BTRFS_PART" | head -1)
[[ -n "$DISK" ]] || DISK=$(echo "$BTRFS_PART" | sed 's/p\?[0-9]*$//')
DISK="/dev/${DISK##*/}"
# EFI / BIOS ブートパーティション検出
EFI_PART=""
BIOS_BOOT_PART=""
if [[ "$BOOT_MODE" == "EFI" ]]; then
EFI_PART=$(lsblk -lnpo NAME,PARTTYPE | \
awk 'tolower($2) == "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" {print $1}' | head -1)
if [[ -z "$EFI_PART" ]]; then
EFI_PART=$(lsblk -lnpo NAME,FSTYPE | awk '$2=="vfat"{print $1}' | head -1)
fi
[[ -n "$EFI_PART" ]] || error "EFIパーティションが見つかりませんでした"
else
BIOS_BOOT_PART=$(lsblk -lnpo NAME,PARTTYPE | \
awk 'tolower($2) == "21686148-6449-6e6f-744e-656564454649" {print $1}' | head -1)
if [[ -z "$BIOS_BOOT_PART" ]]; then
warn "BIOS Bootパーティションが見つかりません(MBRディスクでは正常)"
else
info "BIOS Bootパーティション: $BIOS_BOOT_PART"
fi
fi
# ============================================================
# /boot 独立パーティション検出
# EFI・btrfs 以外の ext2/3/4 → /boot 独立パーティションと判断
# ============================================================
BOOT_PART=""
BOOT_FS=""
for part in $(lsblk -lnpo NAME,FSTYPE "$DISK" | awk '$2 ~ /^ext[234]$/ {print $1}'); do
[[ "$part" == "$EFI_PART" ]] && continue
[[ "$part" == "$BTRFS_PART" ]] && continue
BOOT_PART="$part"
BOOT_FS=$(lsblk -lnpo FSTYPE "$BOOT_PART" | head -1)
break
done
if [[ -n "$BOOT_PART" ]]; then
LAYOUT="3partition"
info "構成B: 3パーティション構成(EFI + /boot独立 + btrfs)"
info "独立 /boot パーティション: $BOOT_PART ($BOOT_FS)"
else
LAYOUT="2partition"
info "構成A: 2パーティション構成(EFI + btrfs)"
fi
# 結果表示
echo ""
echo " 検出結果:"
echo " ┌──────────────────────────────────────────┐"
printf " │ 起動モード : %-21s│\n" "$BOOT_MODE"
printf " │ 構成 : %-21s│\n" "$LAYOUT"
printf " │ Btrfsパーティション : %-21s│\n" "$BTRFS_PART"
if [[ "$BOOT_MODE" == "EFI" ]]; then
printf " │ EFIパーティション : %-21s│\n" "$EFI_PART"
else
printf " │ BIOS Boot : %-21s│\n" "${BIOS_BOOT_PART:-(なし / MBR)}"
fi
printf " │ /boot パーティション: %-21s│\n" "${BOOT_PART:-(なし / btrfs内)}"
printf " │ ディスク : %-21s│\n" "$DISK"
echo " └──────────────────────────────────────────┘"
echo ""
info "ディスク構成(参考):"
lsblk -o NAME,SIZE,FSTYPE,PARTTYPE,MOUNTPOINT "$DISK"
echo ""
warn "上記の検出結果で続行しますか? [yes/N]"
read -r answer
[[ "$answer" == "yes" ]] || { info "中止しました。"; exit 0; }
# ============================================================
# Step 1: マウント
# ============================================================
step "Step 1: Btrfsパーティションをマウント"
info "既存マウントを解除"
for mp in $(findmnt -rno TARGET --source "$BTRFS_PART" 2>/dev/null | sort -r); do
[[ "$mp" == "/" ]] && continue
info " 解除: $mp"
umount "$mp" 2>/dev/null || umount -l "$mp" 2>/dev/null || true
done
if [[ -n "${EFI_PART:-}" ]]; then
for mp in $(findmnt -rno TARGET --source "$EFI_PART" 2>/dev/null | sort -r); do
[[ "$mp" == "/" ]] && continue
info " 解除 (EFI): $mp"
umount "$mp" 2>/dev/null || umount -l "$mp" 2>/dev/null || true
done
fi
if [[ -n "$BOOT_PART" ]]; then
for mp in $(findmnt -rno TARGET --source "$BOOT_PART" 2>/dev/null | sort -r); do
[[ "$mp" == "/" ]] && continue
info " 解除 (/boot): $mp"
umount "$mp" 2>/dev/null || umount -l "$mp" 2>/dev/null || true
done
fi
mkdir -p /mnt
mount "$BTRFS_PART" /mnt
# 二重実行チェック
if btrfs subvolume list /mnt 2>/dev/null | grep -qE '\s@$|\s@home$'; then
error "サブボリューム @ または @home がすでに存在します。移行済みの可能性があります。"
fi
# ============================================================
# Step 2: サブボリューム作成・データ移動
# ============================================================
step "Step 2: サブボリューム作成・データ移動"
cd /mnt
info "スナップショット @ を作成"
btrfs subvolume snapshot . @
# 3パーティション構成: @/boot/ は空のマウントポイントにする
# 2パーティション構成: @/boot/ はそのまま残す(btrfs内にカーネルが必要)
if [[ "$LAYOUT" == "3partition" ]]; then
if [[ -d /mnt/@/boot ]]; then
info "/boot 独立構成のため @/boot/ を空のマウントポイントとして準備"
find /mnt/@/boot -mindepth 1 -delete
fi
fi
info "サブボリューム @home を作成"
btrfs subvolume create @home
if [[ -d /mnt/home ]] && compgen -G "/mnt/home/*" > /dev/null 2>&1; then
info "home/* を @home/ へコピー"
cp -a /mnt/home/. /mnt/@home/
else
warn "home/ が空またはありません。スキップします。"
fi
info "フラットなルートデータを削除"
for entry in /mnt/*; do
name=$(basename "$entry")
[[ "$name" == "@" || "$name" == "@home" ]] && continue
if mountpoint -q "$entry" 2>/dev/null; then
info " アンマウント: $entry"
umount -R "$entry" 2>/dev/null || umount -l "$entry" 2>/dev/null || true
fi
rm -rf "$entry"
info " 削除: $entry"
done
# ============================================================
# Step 3: fstab 書き換え
# ============================================================
step "Step 3: fstab を更新"
FSTAB="/mnt/@/etc/fstab"
[[ -f "$FSTAB" ]] || error "fstab が見つかりません: $FSTAB"
UUID=$(blkid -s UUID -o value "$BTRFS_PART")
[[ -n "$UUID" ]] || error "UUIDの取得に失敗しました"
info "Btrfs UUID: $UUID"
BOOT_UUID=""
if [[ "$LAYOUT" == "3partition" ]]; then
BOOT_UUID=$(blkid -s UUID -o value "$BOOT_PART")
[[ -n "$BOOT_UUID" ]] || error "/boot UUID の取得に失敗しました"
info "/boot UUID: $BOOT_UUID"
fi
cp "$FSTAB" "${FSTAB}.bak"
info "バックアップ: ${FSTAB}.bak"
python3 - "$FSTAB" "$UUID" "$BOOT_UUID" "${BOOT_FS:-}" << 'PYEOF'
import sys, re
fstab_path = sys.argv[1]
uuid = sys.argv[2]
boot_uuid = sys.argv[3]
boot_fs = sys.argv[4]
with open(fstab_path) as f:
lines = f.readlines()
new_lines = []
has_home = False
has_boot = False
for line in lines:
stripped = line.strip()
if stripped.startswith("#") or stripped == "":
new_lines.append(line)
continue
cols = stripped.split()
if len(cols) < 4:
new_lines.append(line)
continue
mountpoint = cols[1]
fstype = cols[2]
if fstype == "btrfs" and mountpoint == "/":
opts = re.sub(r'subvol=[^,\s]+,?', '', cols[3]).strip(',')
opts = (opts + ',subvol=@') if opts else 'defaults,subvol=@'
new_lines.append(f"UUID={uuid} / btrfs {opts} 0 0\n")
elif fstype == "btrfs" and mountpoint == "/home":
opts = re.sub(r'subvol=[^,\s]+,?', '', cols[3]).strip(',')
opts = (opts + ',subvol=@home') if opts else 'defaults,subvol=@home'
new_lines.append(f"UUID={uuid} /home btrfs {opts} 0 0\n")
has_home = True
elif mountpoint == "/boot" and boot_uuid:
new_lines.append(f"UUID={boot_uuid} /boot {boot_fs} defaults 0 2\n")
has_boot = True
else:
new_lines.append(line)
if not has_home:
new_lines.append(f"UUID={uuid} /home btrfs defaults,subvol=@home 0 0\n")
if boot_uuid and not has_boot:
new_lines.append(f"UUID={boot_uuid} /boot {boot_fs} defaults 0 2\n")
with open(fstab_path, 'w') as f:
f.writelines(new_lines)
PYEOF
info "更新後の fstab:"
cat "$FSTAB"
# ============================================================
# Step 4: chroot して GRUB 更新
# ============================================================
step "Step 4: chroot して GRUB を更新"
mkdir -p /mnt2
mount -t btrfs -o subvol=@ "$BTRFS_PART" /mnt2
info "subvol=@ で /mnt2 に再マウント完了"
mkdir -p /mnt2/boot/grub
# 3パーティション構成: chroot前に /boot をマウント
if [[ "$LAYOUT" == "3partition" ]]; then
info "/boot ($BOOT_PART) を /mnt2/boot にマウント"
mkdir -p /mnt2/boot
mount "$BOOT_PART" /mnt2/boot
info " /mnt2/boot の内容:"
ls /mnt2/boot/ || true
fi
mount --rbind /dev /mnt2/dev && mount --make-rslave /mnt2/dev
mount --rbind /proc /mnt2/proc && mount --make-rslave /mnt2/proc
mount --rbind /sys /mnt2/sys && mount --make-rslave /mnt2/sys
mount --rbind /run /mnt2/run && mount --make-rslave /mnt2/run
if [[ "$BOOT_MODE" == "EFI" ]]; then
mount --bind /sys/firmware/efi/efivars /mnt2/sys/firmware/efi/efivars 2>/dev/null || \
warn "efivars のバインドに失敗しました"
mkdir -p /mnt2/boot/efi
mount "$EFI_PART" /mnt2/boot/efi
chroot /mnt2 /bin/bash -e << CHROOT
echo '[chroot] /boot の内容:'
ls /boot/ || true
echo '[chroot] grub-install (EFI) ...'
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck
echo '[chroot] grub-mkconfig ...'
grub-mkconfig -o /boot/grub/grub.cfg
echo '[chroot] subvol 指定確認:'
grep -i subvol /boot/grub/grub.cfg | head -5 || echo '(subvol 指定なし)'
echo '[chroot] 完了'
CHROOT
else
chroot /mnt2 /bin/bash -e << CHROOT
echo '[chroot] /boot の内容:'
ls /boot/ || true
echo '[chroot] grub-install (BIOS) ...'
grub-install --target=i386-pc --recheck $DISK
echo '[chroot] grub-mkconfig ...'
grub-mkconfig -o /boot/grub/grub.cfg
echo '[chroot] subvol 指定確認:'
grep -i subvol /boot/grub/grub.cfg | head -5 || echo '(subvol 指定なし)'
echo '[chroot] 完了'
CHROOT
fi
# ============================================================
# Step 5: アンマウント
# ============================================================
step "Step 5: アンマウント"
umount -R /mnt2 2>/dev/null || true
umount -R /mnt 2>/dev/null || true
echo ""
echo -e "${GREEN}======================================================"
echo " 移行が完了しました!"
echo " 構成: $LAYOUT"
echo " 再起動後に以下で確認してください:"
echo " sudo btrfs subvolume list /"
if [[ "$LAYOUT" == "3partition" ]]; then
echo " findmnt -T /boot"
fi
echo -e "======================================================${NC}"
echo ""
warn "再起動しますか? [yes/N]"
read -r reboot_answer
[[ "$reboot_answer" == "yes" ]] && reboot || info "手動で再起動してください: sudo reboot"
ライブUSBやISOブートで起動するために再起動します。
sudo reboot
ライブUSBやISOブートで起動してスクリプトを実行
次に、インストール時に使用したUbuntuのライブUSB、もしくはISOブートで起動します。
今度は「Ubuntuを試す」を選択し、マウントしたドライブでhomeフォルダ、もしくは/isoフォルダまで辿り、右クリックしてターミナルを開き、保存しておいたスクリプトを実行します。
(失敗すれば起動しなくなります。それでも構わないような、インストール直後に実施を。あくまでも自己責任で!)
sudo bash btrfs_migrate.sh
無事終了したら指示に従い再起動します。

変換後に再度状況を確認
再起動で無事起動したら、先ほどのコマンドを再度実行します。
mount | grep btrfs
下記のような内容なら成功です。
/dev/vda1 on / type btrfs (rw,relatime,discard=async,space_cache=v2,subvolid=256,subvol=/@)
/dev/vda1 on /home type btrfs (rw,relatime,discard=async,space_cache=v2,subvolid=257,subvol=/@home)
管理者権限でBtrfsのサブボリュームの一覧も確認してみましょう。
sudo btrfs subvolume list /
成功していればこのような表示になります。
ID 256 gen 123 top level 5 path @
ID 257 gen 111 top level 5 path @home
Timeshiftインストール
無事サブボリュームが作成されたらTimeshiftをインストールします。
sudo apt update
sudo apt install -y timeshift




インストールが完了したらスナップショットを取りましょう。rsyncの時とは異なり、一瞬で完了します。

復元する時は、Ubutuが起動するならTimeshiftから。起動しない場合はISOブートで起動してTimeshiftをインストールして復元します。GRUBメニューへ追加する方法もありますが、ISOブートやライブUSBで起動して行うほうが確実でしょう。

