萬一將來哪天什麼不幸的事發生了,防災包內的東東可以讓我們一段時日維持基本的需求,裡面該裝些什麼,大家已有許多討論了;資產和錢錢要怎麼避險,放在哪裡較好?我想也有許多人在做了,想起那句經典名言:投資基金有賺有賠,購買前請詳閱公開說明書。
沒網路就讀不到
以上那些資產,我沒有多到要煩惱,不過電腦裡倒是有不少無形的資產,這陣子在慢慢一個個整理並放上網,這些大多是這幾年的服事感想以及一些生活的小記事,除了保存資料,也是跟大家分享。話說,現在很流行把東東放在雲端,因為有網路即可讀取,還可以大家共同編輯文件,不會占用手機或是電腦的硬碟空間更是令人感到輕省,不過,萬一哪天網路斷線了,雲端的東東可是連讀都讀不到喔!當然也無法編輯,所以,重要的資料一定要在本機備份後再上傳網路空間。
帶顆巴掌大的硬碟
萬一哪天要避難了,帶糧食和水就很辛苦了,總不可能再搬一台電腦四處跑,所以,能帶的就是記錄許多東東的硬碟了,不過問題來了,我無法完全地、100%把自己硬碟上的所有東東拿到別人的電腦上去使用,這什麼意思?我硬碟裡的文件、投影片、試算表、影片、音樂…等等,只要對方有相對應的軟體就可以了開啟,如果沒有,就沒輒了!例如別人跟微軟(Microsoft Office)的合約到期不給開.docx檔之類的文件,就算我的硬碟有安裝,一外接到他的電腦去也無法開啟 (LibreOffice就沒到期的問題),換言之,在別人的電腦上,我無法使用自己安裝的文書軟體來開文件!除非用綠色版 (Portable可攜式)的軟體。文書軟體是其中之一,我今天安裝的所有其它軟體只要離開了原本的電腦主機板,就只能望著一堆檔案卻什麼都不能做。
若要開機呼叫硬碟裡的作業系統來跑軟體呢?很抱歉,這就是問題的所在,不同電腦的硬體差異 (尤其晶片組、開機模式、驅動程式) 會使原來的作業系統無法接到別台電腦開機或正常運作。
真 · 行動硬碟
今天,數位防災包正是要做一顆能開機的行動硬碟,它外接到任何一台電腦都可以使用,如同在自己電腦上跑任何已安裝的軟體一樣!這不是普通的 Live USB,而是完整、可更新、可升級、可帶著所有設定與軟體走的真 · Linux系統行動硬碟,要打造把自己舉起來的行動硬碟(Self-Booting Disk),必須先調整一些地方,在此之前,我先整理一下它的威力:
| 功能 | 說明 |
|---|---|
| 🔌 可攜開機 | 插上任何電腦都能直接開機(支援 BIOS + UEFI) |
| 🧠 完整系統 | 不是 Live 模式,而是完整安裝版,有自己的 /, /home, /boot, /efi |
| 💾 資料、設定、軟體全保留 | 瀏覽器、程式、AI 模型、音樂工程、文件全部跟著走 |
| 🧱 完全獨立 | 不讀不寫主機內部的其它硬碟 |
| 🛠️ 可更新、升級 | 一樣能 apt update && apt upgrade,跟一般內裝系統無差別 |
| 🔐 自帶 bootloader | 自己的 GRUB + kernelstub,到哪台機器都能開機 |
| 🧰 具備 BIOS + UEFI 開機雙保險 | 舊筆電、新筆電全通吃 |
| ⚡ 支援 GPU / CUDA / AI 工具 | RTX 4060等顯卡都能發揮(安裝 NVIDIA 驅動後自動偵測) |
與一般 USB Live 系統不同之處
| 項目 | 真行動系統硬碟 | 傳統 Live USB |
|---|---|---|
| 可寫入 | ✅ 可保存資料、設定 | ❌ 重開後消失 |
| 可更新 | ✅ apt upgrade 可用 | ❌ 不建議更新 |
| 可安裝新軟體 | ✅ 完整功能 | ⚠️ 需持久層才行 |
| 開機模式 | BIOS + UEFI | 通常僅 UEFI |
| 獨立性 | ✅ 不依附任何電腦 | ⚠️ 有時改寫主機 EFI |
| 壽命 | SSD/NVMe 長久耐用 | USB 快閃碟壽命有限 |
硬碟不能四處開機的原因:
電腦在安裝作業系統時,除了會把開機程式寫入硬碟,也會在主機板的 UEFI 區裡那塊 NVRAM 登記一筆啟動記錄,當電腦啟動時,UEFI 會依這筆記錄去尋找對應硬碟的開機檔案,若這顆硬碟被拔走,主機板找不到那筆啟動資訊,自然就無法開機。
今天,我們要做的,就是把所有開機資訊都寫在硬碟自己裡面,讓它不再完全依賴主機板。為了避免遇到舊型 BIOS 電腦開不起來,我同時也安裝了 BIOS 版的開機程式,這樣一來,不論是舊機還是新機,通通都能開。
😀 Linux 沒這困擾
Linux並不像Windows把硬碟綁定各個硬體ID,一離開原來安裝的硬體就無法用了,Linux的核心 (kernel) 是隨機偵測硬體、動態載入模組,所以,顯示卡換了會自動下載新的驅動;網卡、音效卡幾乎能自動辨識;主機板和CPU更不用說了,內建自動偵測型號和功能集,因為如此,安裝Linux作業系統是帶著硬碟四處跑,到哪都可以裝到別台電腦上近乎完整使用的防災包首選,沒有之一。
| 問題來源 | 沒做設定時的情況 | 結果 |
|---|---|---|
| 🧱 開機程式 (bootloader) | 預設安裝到當前內建硬碟 | 外接硬碟沒有對上主機板的開機碼,所以拔到別台無法啟動 |
| ⚙️ UEFI 指向錯誤 | EFI 區只登錄在原先那台主機 BIOS 的 NVRAM | 換主機後找不到「開機項目」,變成黑畫面或 No bootable device |
| 💾 BIOS 模式未安裝 | 系統只裝了 grub-efi(UEFI專用),沒有 grub-pc |
舊電腦(Legacy BIOS)完全無法啟動 |
| 🧠 os-prober 未關 | GRUB 偵測到舊主機的開機項 | 換一台主機後就掛了:選單中那些項目路徑失效,開不了機 |
一鍵完成的設定腳本
以下指令都有附說明,Linux有趣的地方就像玩積木,可以把軟體做各種變化和組合,以及寫腳本方便再次使用或者給別人用,執行只要三步驟而已。
-
把指令存檔並命名
portable_boot.sh -
給權限
chmod +x portable_boot.sh -
然後在.sh腳本所在的目錄執行
./portable_boot.sh
這是與AI來回討論後得到的腳本,簡介客製化的特性以及指令做了哪些事。
💡 成品特性
- 插哪台電腦都能開(BIOS / UEFI 皆可)
- 不依賴主機板 NVRAM
- 不影響其它硬碟
- 可備份、可還原、可更新
- 真 · 數位防災行動系統
- 外接盒採用常見的 USB 3.0 介面,理論速度幾乎逼近 2.5 吋 SSD 的上限,實用又方便且不浪費每一分速度。
這支 portable_boot.sh 的需求
- 必備:ESP(UEFI)
- 腳本只會「使用」硬碟的ESP,不會自動建立。
- 需要先在分割硬碟時預留大約300–600 MB 的 FAT32 分割區,並設
boot, esp旗標(常見的大小設為 512 MB)。
- 可選:bios_grub(BIOS)
- 雖然腳本會自動補 2 MiB 的 bios_grub 分割(只限 GPT格式),但最好還是先預留bios_grub分割區,自動補的前提是磁碟開頭或尾端有未分配空間。
- 若整顆磁碟已滿、沒有任何 free space,腳本就沒辦法補;你需先用 GParted 挪出 ≥ 2 MiB 的空白。
簡言之:要先準備ESP;腳本可自動補bios_grub,但要有 2 MiB 空白處且磁碟是 GPT格式。
🗡️ 這支腳本很周到
目的
讓任何 Linux 發行版(Debian / Ubuntu / Pop!_OS …等)能被轉製成「可攜、獨立、雙開機(UEFI + BIOS)」的行動硬碟,並附加完整的 備份 / 還原 / 修復 / 選單互動操作。
🧭 必要步驟與條件
🔍 1. 磁碟偵測與確認
- 自動列出所有可用硬碟與分割表(lsblk + parted)
- 使用者可互動選擇目標硬碟
- 自動判斷:
- GPT 或 MBR 分割表
- Root(系統)分割區
- EFI(FAT32, boot, esp)
- BIOS boot 分割區(bios_grub)
/home是否獨立分割
- 若
/boot/efi沒掛載,會詢問或自動掛載
🧱 2. 檢查 / 建立 BIOS Boot 分割區(bios_grub)
-
若磁碟為 GPT 且無 bios_grub:
- 先嘗試在磁碟開頭(1MiB–3MiB)建立 2MiB bios_grub
- 若開頭已佔滿,再回頭偵測尾端是否有 ≥2MiB 空間可用
- 若空間足夠,自動建立尾端 bios_grub 分割
-
為分割設定旗標:
parted /dev/sdX set N bios_grub on
🧩 3. 確保 EFI 系統分割(ESP)存在
-
若偵測不到 FAT32 boot,esp:
-
提示使用 GParted 建立一個 512MiB~1GiB FAT32 分割區
-
自動設定:
parted /dev/sdX set N boot on parted /dev/sdX set N esp on
-
-
自動掛載至
/mnt/boot/efi或/boot/efi
⚙️ 4. 系統掛載與 chroot 準備
-
將整個目標系統掛載到
/mnt -
綁定
/dev /proc /sys /run -
關閉宿主機的自動更新服務:
systemctl stop packagekit apt-daily.service apt-daily-upgrade.service -
進入 chroot 內部操作(確保環境一致性)
💾 5. 安裝必要工具
在 chroot 內執行:
apt-get update
apt-get install -y \
grub-pc grub-pc-bin \
grub-efi-amd64 grub-efi-amd64-bin shim-signed os-prober
若為 Pop!_OS,還會偵測並執行
kernelstub --force以確保內核與 initrd 被複製進 ESP。
🚀 6. 安裝 GRUB(雙開機)
BIOS 開機碼:
grub-install --target=i386-pc --boot-directory=/boot /dev/sdX
UEFI 開機碼:
grub-install --target=x86_64-efi \
--efi-directory=/boot/efi --boot-directory=/boot \
--recheck --removable
--removable是關鍵,確保即使主機板沒記錄此硬碟的 NVRAM, 也能以/EFI/BOOT/BOOTX64.EFI自行啟動(真正可攜)。
🔒 7. 開機選單獨立化
-
若要完全獨立(不列出別的硬碟系統):
GRUB_DISABLE_OS_PROBER=true -
若要可切換雙系統:
GRUB_DISABLE_OS_PROBER=false
🧩 8. 生成 GRUB 設定
update-grub # 或 grub-mkconfig -o /boot/grub/grub.cfg
🧾 9. 驗證(BIOS + UEFI)
檢查兩項:
-
UEFI 檔案是否存在
ls /boot/efi/EFI/BOOT/BOOTX64.EFI -
MBR 是否含 GRUB 簽名
sudo dd if=/dev/sdX bs=512 count=1 2>/dev/null | strings -a | grep GRUB
兩者皆存在 → ✅「完全獨立可攜系統」
💽 10. (可選)完整備份/還原
- 備份項目:
- MBR / GPT 開頭(前 1MiB)
- 分割表(
sfdisk -d輸出) - ESP(FAT32)
/boot、GRUB 設定與 kernelstub 檔案
- 還原時只需:
- 以 LiveUSB 掛載硬碟
- 導回 MBR + ESP + /boot
- 執行
grub-install+update-grub
✅ 條件與成果
| 條件 | 必要性 | 說明 |
|---|---|---|
| 分割表為 GPT | ✅ 建議 | 為了能同時擁有 bios_grub 與 ESP |
| 有 FAT32(boot,esp) | ✅ 必要 | UEFI 模式開機必需 |
| 有 2MiB 空間建立 bios_grub | ⚙️ 可選 | 若想支援舊 BIOS 機器 |
| 系統能 chroot 進入 | ✅ 必要 | 用於安裝 GRUB 與更新設定 |
| 網路可用 | ⚙️ 建議 | apt 安裝 grub 與 kernelstub |
| 關閉 os-prober | 🔒 建議 | 讓系統完全獨立、不受主機影響 |
portable_boot.sh 腳本
#!/usr/bin/env bash
# portable_boot.sh
# 目的:把一顆 Linux 磁碟(Debian/Ubuntu/Pop!_OS)做成「可攜、獨立、雙開(UEFI+BIOS)」。
# 功能:
# 1) 自動偵測磁碟與分割(ESP/bios_grub/root)
# 2) 若「缺 bios_grub」,在 GPT 磁碟的「開頭或結尾」自動建立 2MiB 的 BIOS Boot 分割(flags=bios_grub)
# 3) 安裝 GRUB(i386-pc + x86_64-efi),並停用 os-prober 讓選單僅保留本機系統(獨立)
# 4) 備份開機資產(MBR/GPT前置、分割表、ESP、/boot、grub、kernelstub)
# 5) 切換獨立/非獨立(關/開 os-prober)
# 使用:
# sudo ./portable_boot.sh # 正式執行
# sudo ./portable_boot.sh --dry-run # 預演,不寫入
set -Eeuo pipefail
shopt -s extglob
# --- 參數:--dry-run 會預演所有步驟,不改動系統 ---
DRY=false; [[ "${1-}" == "--dry-run" ]] && DRY=true && echo "🟡 DRY-RUN:預演模式(不會寫入磁碟)"
# --- 小工具:統一跑指令並顯示 ---
RUN(){ echo "👉 $*"; $DRY || eval "$@"; }
# --- 收尾:確保掛載都卸掉,避免殘留 ---
cleanup(){
echo "🧹 收尾卸載..."
for d in dev proc sys run; do mountpoint -q "/mnt/$d" && umount "/mnt/$d" || true; done
mountpoint -q /mnt/boot/efi && umount /mnt/boot/efi || true
mountpoint -q /mnt && umount /mnt || true
}
trap cleanup EXIT
err(){ echo "❌ $*" >&2; exit 1; }
# ========== 共用輔助 ==========
list_disks(){ echo "📀 可用磁碟(僅列出 TYPE=disk):"; lsblk -d -o NAME,SIZE,MODEL,TYPE | awk '$4=="disk"{printf(" %s %8s %s\n",$1,$2,$3)}'; }
pick_disk(){
list_disks
read -rp "請輸入『目標磁碟』(例:sda 或 nvme0n1): " X
[[ -z "${X:-}" ]] && err "未輸入磁碟"
DISK="/dev/$X"; [[ -b "$DISK" ]] || err "找不到磁碟 $DISK"
echo "🧭 目標磁碟:$DISK"
}
scan_parts(){
echo "🔎 掃描分割:$DISK"
lsblk -o NAME,SIZE,FSTYPE,PARTLABEL,PARTFLAGS,MOUNTPOINT "$DISK"
# 偵測 ESP(vfat,且 flags 含 boot/esp)
ESP_PART="$(lsblk -prno NAME,FSTYPE,PARTFLAGS "$DISK" | awk '/ vfat / && /boot|esp/ {print $1; exit}')"
# 偵測 bios_grub(flags 含 bios_grub)
BIOS_PART="$(lsblk -prno NAME,PARTFLAGS "$DISK" | awk '/bios_grub/ {print $1; exit}')"
# 偵測 root 候選(取同顆磁碟最大的 ext4)
ROOT_PART="$(lsblk -prbo NAME,SIZE,FSTYPE "$DISK" | awk '$3=="ext4"{print $1" "$2}' | sort -k2 -nr | head -1 | awk '{print $1}')"
echo " ➤ ESP(UEFI):${ESP_PART:-<未找到>}"
echo " ➤ BIOS區 :${BIOS_PART:-<未找到>}"
echo " ➤ ROOT候選 :${ROOT_PART:-<未找到>}"
# 允許手動覆蓋
read -rp "覆蓋 ESP(直接輸入 /dev/XXX;留空=使用偵測): " a; [[ -n "${a:-}" ]] && ESP_PART="$a"
read -rp "覆蓋 BIOS(/dev/XXX;留空=使用偵測): " a; [[ -n "${a:-}" ]] && BIOS_PART="$a"
read -rp "覆蓋 ROOT(/dev/XXX;留空=使用偵測): " a; [[ -n "${a:-}" ]] && ROOT_PART="$a"
[[ -n "${ROOT_PART:-}" ]] || err "找不到 root 分割(ext4)。"
[[ -n "${ESP_PART:-}" ]] || err "找不到 ESP(FAT32+boot,esp)。請先用 GParted 建立。"
}
ensure_mounts(){
echo "🗂 掛載 ROOT 與 EFI(準備 chroot)"
RUN "umount -R /mnt 2>/dev/null || true"
RUN "mount $ROOT_PART /mnt"
RUN "mkdir -p /mnt/boot/efi"
RUN "mount $ESP_PART /mnt/boot/efi"
for d in dev proc sys run; do RUN "mount --bind /$d /mnt/$d"; done
}
stop_apt_locks(){
echo "⏸️ 停用自動更新守護程式(避免 apt/dpkg 鎖)"
RUN "systemctl stop packagekit 2>/dev/null || true"
RUN "systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true"
}
fix_dpkg(){
echo "🔧 修復 dpkg/apt 狀態並更新索引"
RUN "chroot /mnt /bin/bash -c 'dpkg --configure -a || true; apt-get -y -f install || true; apt-get update'"
}
install_grub_tools(){
echo "📦 安裝 GRUB 工具(盡量同時準備 BIOS+UEFI;失敗則退而求其次)"
if ! $DRY; then
chroot /mnt /bin/bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y grub-pc grub-pc-bin grub-efi-amd64 grub-efi-amd64-bin shim-signed" || \
chroot /mnt /bin/bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y grub-pc grub-pc-bin || true"
else
echo "(DRY)略過 apt 安裝"
fi
}
disable_os_prober(){
echo "🔒 停用 os-prober(讓 GRUB 『只顯示本機系統』,完全獨立)"
RUN "chroot /mnt /bin/bash -c \"sed -i 's/^#\\?GRUB_DISABLE_OS_PROBER=.*/GRUB_DISABLE_OS_PROBER=true/' /etc/default/grub; grep -q GRUB_DISABLE_OS_PROBER /etc/default/grub || echo GRUB_DISABLE_OS_PROBER=true >> /etc/default/grub\""
}
enable_os_prober(){
echo "🔓 開啟 os-prober(GRUB 會列出其他硬碟上的系統)"
RUN "chroot /mnt /bin/bash -c \"sed -i 's/^#\\?GRUB_DISABLE_OS_PROBER=.*/GRUB_DISABLE_OS_PROBER=false/' /etc/default/grub; grep -q GRUB_DISABLE_OS_PROBER /etc/default/grub || echo GRUB_DISABLE_OS_PROBER=false >> /etc/default/grub\""
}
write_grub(){
echo "💾 安裝 GRUB:BIOS + UEFI"
local disk="/dev/$(lsblk -no pkname "$ROOT_PART")"
[[ -b "$disk" ]] || err "無法推得磁碟於 $ROOT_PART"
# BIOS(需要 bios_grub)
if [[ -n "${BIOS_PART:-}" ]]; then
RUN "chroot /mnt grub-install --target=i386-pc --boot-directory=/boot $disk"
else
echo "⚠️ 未找到 bios_grub;跳過 BIOS 安裝(僅做 UEFI)"
fi
# UEFI
RUN "chroot /mnt grub-install --target=x86_64-efi --efi-directory=/boot/efi --boot-directory=/boot --recheck --removable || true"
}
run_kernelstub_if_exists(){
echo "🧰 Pop!_OS:若有 kernelstub,強制同步 kernel/initrd 到 EFI"
RUN "chroot /mnt /bin/bash -c 'if command -v kernelstub >/dev/null 2>&1; then kernelstub --force || true; fi'"
}
gen_grub_cfg(){
echo "⚙️ 生成 grub.cfg"
RUN "chroot /mnt /bin/bash -c 'update-grub || grub-mkconfig -o /boot/grub/grub.cfg'"
}
# ========== 自動建立 bios_grub(若缺) ==========
# 說明:僅在「磁碟為 GPT」且「有足夠未配置空間」時嘗試建立 2MiB 分割並設 flags=bios_grub
ensure_bios_grub(){
# 先檢查是否已有
if [[ -n "${BIOS_PART:-}" ]]; then
echo "✅ 已存在 bios_grub 分割:$BIOS_PART(略過建立)"
return 0
fi
echo "🧱 未偵測到 bios_grub,嘗試自動建立 2MiB BIOS Boot 分割(僅限 GPT)"
# 檢查分割表型別
local label; label="$(parted -s "$DISK" print | awk -F: '/Partition Table/ {gsub(/^[ \t]+/,"",$2); print $2}')"
[[ "$label" == "gpt" ]] || err "此磁碟非 GPT(目前僅支援 GPT 自動建立 bios_grub)。請改用 GParted 建立後再跑。"
# 取得 free 區資訊(MiB 單位)
local free_head="" free_tail=""
# 開頭 free:查詢 print free 第一個 free 區塊
free_head="$(parted -m "$DISK" unit MiB print free | awk -F: 'NR>2 && $1!~/^[0-9]+$/ && /free/ {gsub(/MiB/,"",$2); gsub(/MiB/,"",$3); print $2,$3; exit}')"
# 結尾 free:取最後一個 free 區塊
free_tail="$(parted -m "$DISK" unit MiB print free | awk -F: 'NR>2 && /free/ {last=$0} END{if(last!=""){split(last,a,":"); gsub(/MiB/,"",a[2]); gsub(/MiB/,"",a[3]); print a[2],a[3]}}')"
create_bios_grub_at(){
local start="$1" end="$2"
echo "🛠️ 嘗試建立 bios_grub:${start}MiB → ${end}MiB"
RUN "parted -s $DISK unit MiB mkpart primary $start $end"
# 取最新分割編號(最後一個分割)
local lastp; lastp="$(lsblk -prno NAME "$DISK" | tail -1)"
RUN "parted -s $DISK set ${lastp##*[^0-9]} bios_grub on"
BIOS_PART="$lastp"
echo "✅ 建立完成:$BIOS_PART(flags=bios_grub)"
}
# 嘗試優先在開頭預留 1→3 MiB;若不足,再在結尾預留 2 MiB
if [[ -n "$free_head" ]]; then
read s e <<<"$free_head"
# 需要至少 3MiB(保留 1→3 的小窗),避免覆蓋 GPT 保護區
if (( $(echo "$e - $s >= 3" | bc -l) )); then
create_bios_grub_at "1" "3"
return 0
fi
fi
if [[ -n "$free_tail" ]]; then
read s e <<<"$free_tail"
# 需要至少 2MiB
if (( $(echo "$e - $s >= 2" | bc -l) )); then
# 從尾端往回 2MiB
local start end
end="$(printf "%.0f" "$e")"
start="$(( end - 2 ))"
create_bios_grub_at "$start" "$end"
return 0
fi
fi
err "找不到可用的未分配空間(≥2MiB)可建立 bios_grub;請手動用 GParted 挪出 2MiB 再跑。"
}
# ========== 備份(含說明檔) ==========
backup_boot_assets(){
echo "📦 建立開機資產備份(MBR/GPT前置、分割表、ESP、/boot、grub、kernelstub)"
read -rp "備份輸出目錄(例:/mnt/usbbackup): " DEST
[[ -n "${DEST:-}" ]] || err "未輸入輸出目錄"
local ts base work
ts="$(date +%Y%m%d-%H%M%S)"
base="boot-backup-$(basename "$DISK")-$(hostname)-$ts"
work="/tmp/$base"
$DRY || mkdir -p "$work" "$DEST"
echo "🧲 備份磁碟前置區(4MiB:MBR/GPT header + 空間)"
RUN "dd if=$DISK of=$work/${base}.first4MiB.img bs=1M count=4 status=none"
echo "📃 匯出分割表(sfdisk)"
RUN "sfdisk -d $DISK > $work/${base}.sfdisk.txt"
echo "📁 備份 ESP 內容"
$DRY || mkdir -p /mnt/esp
RUN "mount $ESP_PART /mnt/esp"
RUN "rsync -aHAX --delete /mnt/esp/ $work/esp/"
RUN "umount /mnt/esp"
echo "🧷 備份 /boot 與 grub 設定"
$DRY || mkdir -p "$work/boot"
[[ -d /boot ]] && RUN "rsync -aHAX /boot/ $work/boot/" || true
[[ -f /etc/default/grub ]] && RUN "cp -a /etc/default/grub $work/" || true
[[ -d /etc/default/grub.d ]] && RUN "rsync -aHAX /etc/default/grub.d $work/" || true
echo "🧰 備份 kernelstub(Pop!_OS)"
RUN "chroot /mnt /bin/bash -c '[ -f /etc/kernelstub/configuration ] && cp -a /etc/kernelstub/configuration /tmp/kernelstub.conf || true'"
$DRY || { [ -f /mnt/tmp/kernelstub.conf ] && cp -a /mnt/tmp/kernelstub.conf "$work/kernelstub.configuration" || true; }
echo "🗜 打包壓縮(tar.gz)"
RUN "tar -C $work -czf $DEST/${base}.tar.gz ."
if ! $DRY; then
echo "✅ 備份完成:$DEST/${base}.tar.gz"
cat > "$DEST/${base}-RESTORE.txt" <<'DOC'
還原指南:
1) 還原分割表(如需重建整顆碟):
sudo sfdisk /dev/sdX < boot-backup-*.sfdisk.txt
2) 還原 ESP 內容:
sudo mount /dev/sdXn_efi /mnt/esp
sudo rsync -aHAX --delete ./esp/ /mnt/esp/
sudo umount /mnt/esp
3) 還原 /boot 與 grub 設定(已 chroot 到該系統):
sudo rsync -aHAX ./boot/ /boot/
sudo cp -a ./grub /etc/default/grub 2>/dev/null || true
sudo rsync -aHAX ./grub.d/ /etc/default/grub.d/ 2>/dev/null || true
4) 重裝 GRUB(雙開):
grub-install --target=i386-pc --boot-directory=/boot /dev/sdX
grub-install --target=x86_64-efi --efi-directory=/boot/efi --boot-directory=/boot --recheck --removable
update-grub || grub-mkconfig -o /boot/grub/grub.cfg
DOC
fi
}
# ========== 動作集合 ==========
action_make_independent_dualboot(){
pick_disk
scan_parts
# 自動補齊 bios_grub(若缺)
ensure_bios_grub
# 按偵測結果掛載並 chroot
ensure_mounts
stop_apt_locks
fix_dpkg
install_grub_tools
disable_os_prober # → 讓它「完全獨立」
write_grub # → 安裝 BIOS + UEFI
run_kernelstub_if_exists # → Pop!_OS 同步 kernel 到 EFI
gen_grub_cfg # → 產生 grub.cfg(只剩本機)
echo "✅ 完成:此系統已成為『可攜、獨立、雙開(UEFI+BIOS)』"
}
action_toggle_isolation(){
pick_disk
scan_parts
ensure_mounts
read -rp "輸入 1=關閉 os-prober(獨立) / 2=開啟 os-prober(列出他系統):[1/2] " m
case "$m" in
1) disable_os_prober ;;
2) enable_os_prober ;;
*) err "輸入無效" ;;
esac
gen_grub_cfg
echo "✅ 已更新 GRUB 選單"
}
action_backup(){
pick_disk
scan_parts
ensure_mounts
backup_boot_assets
}
action_create_bios_grub_only(){
pick_disk
scan_parts
ensure_bios_grub
echo "✅ bios_grub 已就緒:$BIOS_PART"
}
# ========== 主選單 ==========
if [[ "${1-}" != "--dry-run" && -n "${1-}" ]]; then
echo "用法:sudo $0 [--dry-run]"
exit 1
fi
echo "=============================="
echo " 可攜獨立雙開工具 v2(Debian/Ubuntu/Pop!_OS)"
echo "=============================="
echo "1) 讓此系統成為『可攜、獨立、雙開(UEFI+BIOS)』"
echo "2) 切換『獨立/非獨立』(關/開 os-prober)"
echo "3) 備份開機資產(MBR/GPT前置、分割表、ESP、/boot、grub…)"
echo "4) 自動建立 BIOS Boot 分割(若缺,GPT 且有空間)"
echo "q) 離開"
read -rp "請選擇: " choice
case "$choice" in
1) action_make_independent_dualboot ;;
2) action_toggle_isolation ;;
3) action_backup ;;
4) action_create_bios_grub_only ;;
q|Q) echo "bye"; exit 0 ;;
*) err "選項無效" ;;
esac
上次修改於 2025-10-24