> ## Documentation Index
> Fetch the complete documentation index at: https://felimet-hub.jmcores.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WSL Ubuntu 系統搬遷指南

> 把佔用 C 槽空間的 WSL Ubuntu 完整搬遷至其他磁碟機：以 wsl --export / --import 封裝與重新部署，保留所有軟體與設定，並釋放系統碟空間。

export const TerminalDemo = ({lang = "zh", title, prompt, commands}) => {
  const L = ({
    zh: {
      play: "播放",
      pause: "暫停",
      step: "下一步",
      replay: "重新播放",
      reset: "重設",
      winTitle: "Windows PowerShell",
      hint: "點播放，逐行看驗證流程實際跑出來的樣子"
    },
    en: {
      play: "Play",
      pause: "Pause",
      step: "Step",
      replay: "Replay",
      reset: "Reset",
      winTitle: "Windows PowerShell",
      hint: "Press play to watch the verification run line by line"
    }
  })[lang] || ({});
  const defaultCmds = [{
    cmd: "nvidia-smi",
    output: ["Mon Jun  8 14:30:12 2026", "+-----------------------------------------------------------------------------+", "| NVIDIA-SMI 552.22       Driver Version: 552.22       CUDA Version: 12.4     |", "|-------------------------------+----------------------+----------------------+", "| GPU  Name           TCC/WDDM  | Bus-Id        Disp.A | Volatile Uncorr. ECC |", "| Fan  Temp Perf Pwr:Usage/Cap  | Memory-Usage         | GPU-Util  Compute M. |", "|===============================+======================+======================|", "|   0  GeForce RTX 3080  WDDM   | 00000000:01:00.0  On |                  N/A |", "| 30%   42C  P8    21W / 320W   |    842MiB / 10240MiB |      2%      Default |", "+-------------------------------+----------------------+----------------------+"]
  }, {
    cmd: "nvcc -V",
    output: ["nvcc: NVIDIA (R) Cuda compiler driver", "Copyright (c) 2005-2024 NVIDIA Corporation", "Built on Tue_Feb_27_16:28:36_2024", "Cuda compilation tools, release 12.4, V12.4.99", "Build cuda_12.4.r12.4/compiler.34097967_0"]
  }, {
    cmd: "python gpu_test.py",
    output: ["========================================", "PyTorch Version: 2.6.0+cu124", "CUDA Available:  True", "Device Name:     NVIDIA GeForce RTX 3080", "CUDA Version:    12.4", "✓ cuDNN Test Passed! Convolution executed successfully.", "========================================"]
  }];
  const raw = commands && commands.length ? commands : defaultCmds;
  const cmds = raw.map(c => ({
    cmd: c.cmd,
    lines: Array.isArray(c.output) ? c.output : String(c.output || "").split("\n")
  }));
  const PROMPT = prompt || "PS C:\\Users\\dev>";
  const TITLE = title || L.winTitle;
  const [idx, setIdx] = useState(0);
  const [typed, setTyped] = useState(0);
  const [outN, setOutN] = useState(0);
  const [stage, setStage] = useState("cmd");
  const [running, setRunning] = useState(false);
  const [done, setDone] = useState(false);
  useEffect(() => {
    if (!running || done) return;
    const cur = cmds[idx];
    if (!cur) {
      setRunning(false);
      setDone(true);
      return;
    }
    if (stage === "cmd") {
      if (typed < cur.cmd.length) {
        const id = setTimeout(() => setTyped(typed + 1), 28);
        return () => clearTimeout(id);
      }
      const id = setTimeout(() => setStage("out"), 200);
      return () => clearTimeout(id);
    }
    if (stage === "out") {
      if (outN < cur.lines.length) {
        const id = setTimeout(() => setOutN(outN + 1), 70);
        return () => clearTimeout(id);
      }
      const id = setTimeout(() => {
        if (idx + 1 < cmds.length) {
          setIdx(idx + 1);
          setTyped(0);
          setOutN(0);
          setStage("cmd");
        } else {
          setRunning(false);
          setDone(true);
        }
      }, 360);
      return () => clearTimeout(id);
    }
  }, [running, done, idx, typed, outN, stage]);
  const reset = () => {
    setRunning(false);
    setDone(false);
    setIdx(0);
    setTyped(0);
    setOutN(0);
    setStage("cmd");
  };
  const playPause = () => {
    if (done) {
      reset();
      setRunning(true);
      return;
    }
    setRunning(!running);
  };
  const step = () => {
    setRunning(false);
    if (done) return;
    if (idx + 1 < cmds.length) {
      setIdx(idx + 1);
      setTyped(0);
      setOutN(0);
      setStage("cmd");
    } else {
      const cur = cmds[idx];
      setTyped(cur.cmd.length);
      setOutN(cur.lines.length);
      setStage("out");
      setDone(true);
    }
  };
  const css = `
.td-root{--bg:#f4eee4;--bd:#e2d7c6;--ink:#5b5048;--accent:#bf7551;--accent-l:#cf8a68;
  --scr:#1c1815;--scr-fg:#e9e1d4;--scr-prompt:#cf8a68;--scr-dim:#8d8478;--scr-ok:#8fb573;--scr-err:#d98a72;
  border:1px solid var(--bd);border-radius:14px;overflow:hidden;background:var(--bg);
  font-family:ui-sans-serif,system-ui,"Noto Sans TC",sans-serif;margin:1.25rem 0;box-shadow:0 1px 2px rgba(60,40,25,.06);}
.dark .td-root{--bg:#26221e;--bd:#3a332c;--ink:#cabfb2;}
.td-bar{display:flex;align-items:center;gap:.6rem;padding:.55rem .8rem;background:linear-gradient(var(--bg),color-mix(in srgb,var(--bg) 90%,#000));border-bottom:1px solid var(--bd);}
.td-dots{display:flex;gap:.4rem;}
.td-dots i{width:11px;height:11px;border-radius:50%;display:block;}
.td-dots i:nth-child(1){background:#d98a72;} .td-dots i:nth-child(2){background:#dcb46a;} .td-dots i:nth-child(3){background:#8fb573;}
.td-title{font-size:.78rem;color:var(--ink);font-weight:600;letter-spacing:.01em;flex:1;text-align:center;opacity:.85;}
.td-ctrl{display:flex;align-items:center;gap:.3rem;}
.td-btn{display:inline-flex;align-items:center;gap:.32rem;border:1px solid var(--bd);background:transparent;color:var(--ink);
  border-radius:8px;padding:.3rem .55rem;font-size:.74rem;font-weight:600;cursor:pointer;transition:all .15s ease;line-height:1;}
.td-btn:hover{border-color:var(--accent);color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent);}
.td-btn svg{width:13px;height:13px;}
.td-btn--primary{background:var(--accent);border-color:var(--accent);color:#fff;}
.dark .td-btn--primary{background:var(--accent-l);border-color:var(--accent-l);}
.td-btn--primary:hover{background:var(--accent-l);color:#fff;}
.td-count{font-size:.72rem;color:var(--ink);opacity:.6;font-variant-numeric:tabular-nums;margin-left:.2rem;}
.td-screen{background:var(--scr);color:var(--scr-fg);padding:.85rem 1rem 1.05rem;font-family:ui-monospace,"Cascadia Code","Consolas",monospace;
  font-size:.8rem;line-height:1.55;overflow-x:auto;min-height:120px;}
.td-block{margin-bottom:.5rem;}
.td-cmdline{white-space:pre;}
.td-prompt{color:var(--scr-prompt);font-weight:600;}
.td-cmd{color:#f3ecdf;}
.td-out{white-space:pre;color:var(--scr-fg);opacity:.92;}
.td-out.ok{color:var(--scr-ok);font-weight:600;}
.td-out.err{color:var(--scr-err);font-weight:600;}
.td-cursor{display:inline-block;width:8px;height:1em;background:var(--scr-prompt);margin-left:1px;vertical-align:text-bottom;
  animation:tdblink 1s steps(2,start) infinite;}
@keyframes tdblink{to{opacity:0;}}
.td-hint{padding:.5rem .9rem;font-size:.72rem;color:var(--ink);opacity:.6;border-top:1px solid var(--bd);background:var(--bg);}
@media (max-width:600px){.td-screen{font-size:.68rem;} .td-title{display:none;} .td-btn{padding:.28rem .42rem;}}
`;
  const PlayIcon = () => <svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M7 5.5v13l11-6.5z" /></svg>;
  const PauseIcon = () => <svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><rect x="6.5" y="5" width="4" height="14" rx="1" /><rect x="13.5" y="5" width="4" height="14" rx="1" /></svg>;
  const StepIcon = () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 4l10 8-10 8z" /><line x1="19" y1="5" x2="19" y2="19" /></svg>;
  const ResetIcon = () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8" /><path d="M3 3v5h5" /></svg>;
  const shown = Math.min(idx + (done ? 1 : 0), cmds.length);
  return <div className="td-root">
      <style>{css}</style>
      <div className="td-bar">
        <span className="td-dots"><i /><i /><i /></span>
        <span className="td-title">{TITLE}</span>
        <span className="td-ctrl">
          <button className="td-btn td-btn--primary" onClick={playPause}>
            {running ? <PauseIcon /> : <PlayIcon />}
            {done ? L.replay : running ? L.pause : L.play}
          </button>
          <button className="td-btn" onClick={step} disabled={done}><StepIcon />{L.step}</button>
          <button className="td-btn" onClick={reset}><ResetIcon />{L.reset}</button>
          <span className="td-count">{shown}/{cmds.length}</span>
        </span>
      </div>
      <div className="td-screen">
        {Array.from({
    length: idx + 1
  }).map((_, i) => {
    const c = cmds[i];
    if (!c) return null;
    const isCur = i === idx;
    const cmdText = isCur ? c.cmd.slice(0, typed) : c.cmd;
    const lines = isCur ? c.lines.slice(0, outN) : c.lines;
    const cursor = isCur && !done && stage === "cmd";
    return <div className="td-block" key={i}>
              <div className="td-cmdline">
                <span className="td-prompt">{PROMPT}</span> <span className="td-cmd">{cmdText}</span>
                {cursor && <span className="td-cursor" />}
              </div>
              {lines.map((ln, j) => {
      const tr = ln.trim();
      const cls = tr.startsWith("✓") ? "ok" : tr.startsWith("✗") || tr.startsWith("✘") ? "err" : "";
      return <div className={"td-out " + cls} key={j}>{ln.length ? ln : " "}</div>;
    })}
            </div>;
  })}
      </div>
      <div className="td-hint">{L.hint}</div>
    </div>;
};

`WSL` `Ubuntu` `Windows`

把佔用大量 C 槽空間的 WSL Ubuntu 完整遷移到其他磁碟機，釋放系統碟空間，同時保留所有已安裝的軟體與設定。原理是用 `wsl --export` 封裝成 tar、`wsl --import` 部署到新位置，再切換預設並清理舊安裝。

<Note>
  搬遷過程會暫時停止 WSL 服務，建議在非工作時段進行。整個流程約 30 分鐘至 2 小時，視系統大小而定。
</Note>

## 搬遷前準備

### 系統需求

| 項目         | 最低需求             | 建議規格            | 說明            |
| ---------- | ---------------- | --------------- | ------------- |
| 磁碟空間       | Ubuntu 大小 × 1.2  | Ubuntu 大小 × 1.5 | 目標磁碟機需有充足空間   |
| 系統記憶體      | 4GB              | 8GB 以上          | 大型系統搬遷需更多記憶體  |
| Windows 版本 | Windows 10 v1903 | Windows 11      | 較新版本 WSL 支援更佳 |
| 使用者權限      | 一般使用者            | 系統管理員           | 管理員權限可避免權限問題  |

### 資料備份策略

搬遷相對安全，但建議先做預防措施。

<Tabs>
  <Tab title="重要資料備份">
    搬遷時 Ubuntu 會被完整封裝再重新部署。建議將重要使用者資料另外備份至雲端或外部儲存，特別注意：

    * `/home/<username>/`：使用者主目錄
    * `/opt/`：第三方軟體安裝目錄
    * 自訂設定檔
  </Tab>

  <Tab title="系統還原點">
    可建立 Windows 系統還原點，極端情況能回復至搬遷前狀態：

    1. 開啟「系統保護」設定
    2. 選擇系統磁碟機
    3. 建立還原點並加描述標籤
  </Tab>
</Tabs>

<Warning>
  為搬遷預留足夠時間，過程中不要中斷電源或關閉系統。
</Warning>

## 詳細搬遷步驟

<Steps>
  <Step title="系統狀態檢查">
    以系統管理員開啟 PowerShell，列出所有 WSL 發行版（名稱、狀態、WSL 版本、預設標記）：

    ```powershell theme={null}
    wsl -l -v
    ```

    <Note>記下確切的發行版名稱（如 `Ubuntu-22.04`），後續步驟會用到。</Note>
  </Step>

  <Step title="封裝 Ubuntu 系統">
    將現有 Ubuntu 封裝成可攜的 tar 檔（依實際發行版名稱與目標路徑調整）：

    ```powershell theme={null}
    wsl --export Ubuntu-22.04 D:\ubuntu-22.04-backup.tar
    ```

    | 參數                           | 範例值   | 說明         |
    | ---------------------------- | ----- | ---------- |
    | `Ubuntu-22.04`               | 發行版名稱 | 步驟 1 確認的名稱 |
    | `D:\ubuntu-22.04-backup.tar` | 封裝路徑  | 備份檔完整路徑與檔名 |

    <Warning>封裝程序不顯示進度且持續運行，請耐心等候，勿中斷或關閉視窗。可觀察目標檔案大小變化來監控進展。</Warning>
  </Step>

  <Step title="部署到新位置">
    建立搬遷後的 Ubuntu 實例：

    ```powershell theme={null}
    wsl --import Ubuntu-22.04-diskD D:\Ubuntu-22.04-diskD D:\ubuntu-22.04-backup.tar
    ```

    參數依序為：新實例名稱（可自訂）、系統檔案實際存放資料夾、步驟 2 的封裝檔路徑。命名建議用描述性名稱（如 `Ubuntu-DataDisk`），避免特殊字元與空格。部署後再跑一次 `wsl -l -v` 確認新實例出現在清單。
  </Step>

  <Step title="設定預設並修正使用者">
    將預設 WSL 發行版切到新實例：

    ```powershell theme={null}
    wsl --setdefault Ubuntu-22.04-diskD
    ```

    <Warning>
      **`wsl --import` 後預設使用者會變成 root**（匯入的發行版不保留原預設使用者）。在新實例內建立 `/etc/wsl.conf` 指定預設使用者，再 `wsl --shutdown` 重啟即可恢復一般帳號登入：

      ```ini theme={null}
      [user]
      default=<你的使用者名稱>
      ```
    </Warning>

    驗證可正常啟動：

    ```powershell theme={null}
    wsl
    ```
  </Step>

  <Step title="清理舊系統">
    確認新環境完全正常後，移除原有 Ubuntu 釋放 C 槽：

    ```powershell theme={null}
    wsl --unregister Ubuntu-22.04
    ```

    <Warning>此步驟永久刪除原有 Ubuntu 安裝，務必確認新環境正常運作後再執行。</Warning>

    可用磁碟清理工具檢視 C 槽空間增量、確認 WSL 資料夾已移除、`wsl -l -v` 確認舊發行版已消失。tar 封裝檔可保留一段時間當額外備份，確認穩定後再刪：

    ```powershell theme={null}
    del D:\ubuntu-22.04-backup.tar
    ```
  </Step>
</Steps>

完整搬遷流程跑起來大致是這樣，從確認來源、封裝、部署到驗證新實例：

<TerminalDemo
  lang="zh"
  title="Windows PowerShell"
  prompt={"PS C:\\>"}
  commands={[
{
  cmd: "wsl -l -v",
  output: [
    "  NAME            STATE           VERSION",
    "* Ubuntu-22.04    Running         2",
  ],
},
{
  cmd: "wsl --export Ubuntu-22.04 D:\\ubuntu-22.04-backup.tar",
  output: [
    "正在匯出發行版，這可能需要幾分鐘...",
    "操作順利完成。",
  ],
},
{
  cmd: "wsl --import Ubuntu-22.04-diskD D:\\Ubuntu-22.04-diskD D:\\ubuntu-22.04-backup.tar",
  output: [
    "正在匯入發行版...",
    "操作順利完成。",
  ],
},
{
  cmd: "wsl -l -v",
  output: [
    "  NAME                  STATE           VERSION",
    "* Ubuntu-22.04          Stopped         2",
    "  Ubuntu-22.04-diskD    Stopped         2",
  ],
},
]}
/>

## 疑難排解

<Tabs>
  <Tab title="封裝失敗">
    | 問題原因         | 檢查方法        | 解決方案                 |
    | ------------ | ----------- | -------------------- |
    | 磁碟空間不足       | 檢查目標磁碟可用空間  | 清理空間或換磁碟             |
    | 權限不足         | 確認以管理員執行    | 以管理員重開 PowerShell    |
    | Ubuntu 未完全關閉 | 檢查 WSL 執行狀態 | `wsl --shutdown` 後重試 |
  </Tab>

  <Tab title="部署錯誤">
    依序檢查：

    1. 驗證 tar 完整性：`wsl --list --verbose`
    2. 清理殘留實例：`wsl --unregister Ubuntu-22.04-diskD`
    3. 重新部署：`wsl --import Ubuntu-22.04-diskD D:\Ubuntu-22.04-diskD D:\ubuntu-22.04-backup.tar`
  </Tab>

  <Tab title="啟動異常">
    新環境無法啟動時：

    1. 檢查所有實例狀態：`wsl --list --verbose`
    2. 強制終止問題實例：`wsl --terminate Ubuntu-22.04-diskD`
    3. 啟動特定發行版：`wsl --distribution Ubuntu-22.04-diskD`
  </Tab>
</Tabs>

### 緊急復原

搬遷出現嚴重問題且無法修復時：

1. 驗證原始 tar 封裝檔存在且未損壞
2. 清理問題實例：`wsl --unregister Ubuntu-22.04-diskD`
3. 用相同部署指令重新建立
4. 仍有問題可暫時恢復使用原有實例直到解決

<Warning>復原會回到搬遷前狀態，但會失去搬遷過程中的任何變更，請謹慎評估後執行。</Warning>
