Day 3:命令列工具 — 掌握 NixOS 日常操作的瑞士刀
深入 NixOS 命令列工具箱,詳解 nixos-rebuild 的各種子指令、nix-env 的使用方式,以及如何清理舊 generation 與臨時試用套件。
Day 3:命令列工具 — 掌握 NixOS 日常操作的瑞士刀
🗓 系列:NixOS 30 天學習之旅
📦 階段:第一階段 — 基礎與生存守則(Day 1 – Day 7)
🎯 階段核心目標:理解 Declarative 配置與 Immutability
前言
在 Day 1,我們理解了 NixOS 的核心觀念——Nix Store、Declarative 配置、Generational Rollback。Day 2,我們動手編輯了 configuration.nix,學會安裝套件、管理使用者、開啟 SSH 服務,最後用 sudo nixos-rebuild switch 讓變更生效。
但你有沒有想過:nixos-rebuild switch 到底做了什麼?除了 switch,還有哪些子指令?舊的 generation 一直留在硬碟上,怎麼清理?如果我只想臨時裝一個工具試用,一定要改 configuration.nix 嗎?
今天,我們要深入 NixOS 的命令列工具箱,熟悉你在日常操作中一定會用到的幾把瑞士刀:
nixos-rebuild— 套用配置的核心指令nix-env— 使用者層級的套件管理(有爭議,但你得認識它)nix-collect-garbage— 清理舊世代與無用的 store path- 其他實用指令 —
nix-store、nixos-version等
學完今天的內容,你就能自信地操作 NixOS,而不是只會那一招 nixos-rebuild switch。
nixos-rebuild 完全解析
nixos-rebuild 是 NixOS 上最重要的指令,沒有之一。每次你修改了 configuration.nix,都需要透過它來讓變更生效。但「生效」這件事,其實有好幾種模式。
五種子指令一覽
sudo nixos-rebuild <子指令>
| 子指令 | 行為 | 適用情境 |
|---|---|---|
switch | Build → 切換到新 generation → 重啟受影響的 service | 日常使用,最常見 |
boot | Build → 設為下次開機的 generation,但不立即切換 | 想在下次重開機時才套用變更 |
test | Build → 立即切換,但不寫入 bootloader | 想先測試配置,重開機後會回到原本的 generation |
build | 只 build,不切換也不寫入 bootloader | 想確認配置能不能成功 build |
dry-build | 只做 evaluation,列出「會 build 什麼」,但不實際 build | 快速預覽變更範圍 |
讓我們逐一拆解。
switch — 你的日常主力
sudo nixos-rebuild switch
這是最常用的指令。它會:
- 評估(evaluate)
/etc/nixos/configuration.nix - 建置(build)所有需要的 derivation
- 建立一個新的 generation
- 將系統切換到新的 generation
- 重新啟動受影響的 systemd service
- 更新 bootloader(GRUB 或 systemd-boot),讓新 generation 成為預設的開機選項
一句話:改完設定、確定要套用,就用 switch。
boot — 下次開機再說
sudo nixos-rebuild boot
和 switch 幾乎一樣,但差別在於不會立即切換到新的 generation。新的配置會被寫入 bootloader,等到你下次重開機時才會生效。
適用情境:
- 改了 kernel 設定或 bootloader 配置,本來就需要重開機
- 正在跑重要的 service,不想馬上重啟它們
test — 試一下,不滿意就重開機
sudo nixos-rebuild test
test 會立即切換到新的配置(包括重啟 service),但不會更新 bootloader。也就是說,如果你重開機,系統會回到上一個寫入 bootloader 的 generation。
這很適合用來「試水溫」——先在目前的 session 中測試新配置,確認沒問題後再用 switch 正式套用。
# 先試一下
sudo nixos-rebuild test
# 確認一切正常後,正式套用
sudo nixos-rebuild switch
build — 只 build,不碰系統
sudo nixos-rebuild build
只執行 build 步驟,產出的結果會放在當前目錄下的 ./result symlink 中,但完全不會影響正在運行的系統。
適合用來:
- 在正式套用之前,確認整份配置能成功 build
- 在 CI/CD pipeline 中驗證 NixOS 配置的正確性
sudo nixos-rebuild build
# 成功的話,./result 會指向新的 system derivation
ls -la ./result
dry-build — 最輕量的預覽
sudo nixos-rebuild dry-build
連 build 都不做,只執行 evaluation,然後列出「哪些東西需要被 build 或從 cache 下載」。速度最快,適合在改完配置後快速確認變更範圍。
sudo nixos-rebuild dry-build
# 輸出大概像這樣:
# these 3 derivations will be built:
# /nix/store/abc123...-nginx-1.25.3.drv
# /nix/store/def456...-system-path.drv
# /nix/store/ghi789...-nixos-system-my-nixos-24.05.drv
搭配 --rollback 快速回滾
前面提到的回滾機制,就是搭配 switch 或 boot 使用:
# 回滾到上一個 generation 並立即切換
sudo nixos-rebuild switch --rollback
# 回滾到上一個 generation,下次開機才生效
sudo nixos-rebuild boot --rollback
搭配 --upgrade 更新 channel
如果你想同時更新 Nix channel(類似於 apt update)再 rebuild:
sudo nixos-rebuild switch --upgrade
這等同於先跑 nix-channel --update,再跑 nixos-rebuild switch。
nix-env 基本操作(認識但不推薦)
在進入這一節之前,先說一個重要的觀念:
⚠️ 在 NixOS 上,
nix-env是一個你應該認識、但盡量少用的工具。
為什麼?因為 nix-env 是 imperative 的——它讓你像用 apt install 一樣直接安裝套件,但這些操作不會反映在 configuration.nix 裡。這就破壞了 NixOS 最核心的 declarative 精神:你的系統狀態應該完全由配置檔定義。
話雖如此,你還是需要認識它,因為:
- 很多教學文章和論壇回答會提到
nix-env - 有時候你就是想臨時裝個工具試用,不想改
configuration.nix - 理解它能幫助你更深入理解 Nix 的 profile 機制
基本操作
# 搜尋套件
nix-env -qaP | grep ripgrep
# 輸出:nixos.ripgrep ripgrep-14.1.0
# 安裝套件(到使用者的 profile 中)
nix-env -iA nixos.ripgrep
# 列出已安裝的套件
nix-env -q
# 輸出:ripgrep-14.1.0
# 升級所有已安裝的套件
nix-env -u
# 移除套件
nix-env -e ripgrep
# 列出目前使用者的所有 generation
nix-env --list-generations
nix-env 的 generation
和系統的 generation 類似,nix-env 也會為每個使用者維護獨立的 generation。每次安裝或移除套件,都會產生新的 generation:
nix-env --list-generations
# 1 2024-03-10 10:00:00
# 2 2024-03-10 10:05:00 (current)
# 回滾到上一個使用者 profile 的 generation
nix-env --rollback
那應該用什麼替代?
| 情境 | 推薦做法 |
|---|---|
| 系統層級安裝套件 | 寫在 configuration.nix 的 environment.systemPackages |
| 使用者層級管理套件 | 使用 home-manager(後續章節會介紹) |
| 臨時需要某個工具 | nix-shell -p <package>(開一個臨時 shell,退出後自動清除) |
特別推薦 nix-shell 的用法:
# 臨時需要用 jq 處理 JSON,但不想永久安裝
nix-shell -p jq
# 進入臨時 shell 後,jq 就可以用了
echo '{"name":"nix"}' | jq '.name'
# 輸出:"nix"
# 按 Ctrl+D 或輸入 exit 離開,jq 就「消失」了
這才是 NixOS 的風格——需要的時候拿來用,用完乾淨離開,不留痕跡。
nix-collect-garbage — 清理舊世代
隨著你不斷修改配置、執行 nixos-rebuild switch,系統會累積越來越多的 generation。每個 generation 都會在 /nix/store 中保留對應的套件和設定,磁碟空間會逐漸被占據。
這時候就需要 garbage collection。
基本用法
# 刪除所有舊的 generation(只保留目前正在使用的)
sudo nix-collect-garbage -d
-d 是 --delete-old 的縮寫,它會:
- 刪除所有舊的 system generation(除了目前啟用的)
- 刪除所有舊的 user profile generation
- 執行 garbage collection,清除
/nix/store中不再被任何 generation 參照的路徑
⚠️ 注意:執行
-d後,你就無法再回滾到舊的 generation 了!確認目前系統沒問題後再執行。
只清理 store,保留 generation
如果你只想清理 /nix/store 中沒被參照的檔案,但保留所有 generation profile:
sudo nix-collect-garbage
# 不加 -d,只做 garbage collection
不過這通常清不出太多空間,因為舊的 generation 仍然在參照那些路徑。
保留最近幾天的 generation
比起粗暴地刪掉所有舊 generation,更實際的做法是保留一段時間內的 generation:
# 刪除 7 天前的所有 generation,然後清理
sudo nix-collect-garbage --delete-older-than 7d
# 刪除 30 天前的 generation
sudo nix-collect-garbage --delete-older-than 30d
這樣既能釋放空間,又保留了近期的回滾能力。
搭配 nix-store --gc 使用
nix-store --gc 是更底層的 garbage collection 指令:
# 執行 garbage collection
nix-store --gc
# 查看 garbage collection 可以釋放多少空間(dry run)
nix-store --gc --print-dead
設定自動清理
你也可以在 configuration.nix 中設定自動清理,讓系統定期自動執行 garbage collection:
# 每週自動清理 30 天前的 generation
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};
這樣就不用手動記得清理了,非常推薦在任何 NixOS 系統上啟用。
其他實用指令
除了上面三大主力,還有幾個你遲早會用到的指令。
nixos-version — 查看系統版本
nixos-version
# 輸出:24.05.20240315.abc1234 (Uakari)
輸出包含 NixOS 版本號、commit hash 和 codename。在你到社群提問或回報問題時,記得附上這個資訊。
nix-store — 查詢 store 路徑
nix-store 可以幫助你理解套件之間的相依關係:
# 查詢某個套件的所有 dependencies(遞迴)
nix-store -qR $(which git)
# 查詢某個套件的直接 dependencies
nix-store -q --references $(which git)
# 查詢「誰」依賴了這個套件
nix-store -q --referrers /nix/store/xxx...-openssl-3.0.12
# 查看某個 store path 佔了多少空間(含 dependencies)
nix path-info -Sh $(which git)
nix-channel — 管理 channel
Channel 是 NixOS 取得套件定義的來源,類似於 Ubuntu 的 apt source:
# 列出目前的 channel
sudo nix-channel --list
# 輸出:nixos https://channels.nixos.org/nixos-25.1
# 更新 channel(拉取最新的套件定義)
sudo nix-channel --update
# 新增一個 channel
sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable
nixos-option — 查詢可用的配置選項
不確定某個設定的完整語法?用 nixos-option 來查:
# 查詢 services.openssh 的所有選項
nixos-option services.openssh
# 查詢某個選項的預設值與說明
nixos-option services.openssh.settings.PermitRootLogin
或者直接到 search.nixos.org/options 網頁搜尋,資訊更完整也更好閱讀。
系統 generation 管理
# 列出所有系統 generation
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
# 查看目前系統的 generation 編號
readlink /nix/var/nix/profiles/system
實戰練習
學了這麼多指令,來動手練習一下吧!依照以下步驟操作,確認你對每個指令都有實際的體感。
練習一:預覽 → 測試 → 正式套用
# Step 1:在 configuration.nix 中新增一個套件,例如 tree
sudo nano /etc/nixos/configuration.nix
# 在 environment.systemPackages 加入 tree
# Step 2:先用 dry-build 看看會影響什麼
sudo nixos-rebuild dry-build
# Step 3:用 test 模式試跑(不寫入 bootloader)
sudo nixos-rebuild test
# Step 4:確認 tree 可以使用
tree --version
# Step 5:滿意的話,正式套用
sudo nixos-rebuild switch
練習二:體驗 nix-shell 的臨時環境
# 不修改任何配置,臨時使用 cowsay
nix-shell -p cowsay
# 在臨時 shell 中
cowsay "NixOS is awesome!"
# 離開臨時 shell
exit
# 確認 cowsay 已經不見了
which cowsay
# 輸出:cowsay not found
練習三:查看 generation 並清理
# 查看目前有多少個系統 generation
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
# 查看 store 的磁碟使用量
df -h /nix/store
# 清理 7 天前的 generation
sudo nix-collect-garbage --delete-older-than 7d
# 再次確認磁碟使用量
df -h /nix/store
練習四:探索套件的相依關係
# 查看 vim 依賴了哪些套件
nix-store -qR $(which vim) | head -20
# 查看 vim 佔了多少空間(含所有 dependencies)
nix path-info -Sh $(which vim)
指令速查表
把今天學到的指令整理成一張表,方便日後速查:
| 指令 | 用途 |
|---|---|
sudo nixos-rebuild switch | 套用配置並立即切換 |
sudo nixos-rebuild boot | 套用配置,下次開機生效 |
sudo nixos-rebuild test | 立即切換但不寫入 bootloader |
sudo nixos-rebuild build | 只 build,不影響系統 |
sudo nixos-rebuild dry-build | 預覽會 build 什麼 |
sudo nixos-rebuild switch --rollback | 回滾到上一個 generation |
sudo nixos-rebuild switch --upgrade | 更新 channel 並套用 |
nix-env -iA nixos.<pkg> | 安裝套件到使用者 profile |
nix-env -q | 列出使用者已安裝的套件 |
nix-env -e <pkg> | 移除使用者套件 |
nix-env --list-generations | 列出使用者 profile 的 generation |
nix-shell -p <pkg> | 開啟含有指定套件的臨時 shell |
sudo nix-collect-garbage -d | 刪除所有舊 generation 並清理 |
sudo nix-collect-garbage --delete-older-than 7d | 清理 7 天前的 generation |
nix-store --gc --print-dead | 預覽可釋放的空間 |
nix-store -qR <path> | 查看某路徑的所有 dependencies |
nixos-version | 查看系統版本 |
nixos-option <option> | 查詢配置選項說明 |
小結
今天我們全面盤點了 NixOS 的命令列工具箱:
| 工具 | 角色 |
|---|---|
nixos-rebuild | 系統配置的核心執行器,有 switch、boot、test、build、dry-build 五種模式 |
nix-env | 使用者層級的 imperative 套件管理,認識即可,日常建議用 configuration.nix 或 nix-shell 替代 |
nix-collect-garbage | 清理舊世代與無用的 store path,建議搭配 --delete-older-than 使用 |
nix-store / nix-channel | 底層工具,用來查詢相依關係與管理套件來源 |
記住一個原則:能用 declarative 的方式就不要用 imperative。把設定寫在 configuration.nix,用 nixos-rebuild 套用,這才是 NixOS 的正道。
明日預告
Day 4:Nix 語言入門 — configuration.nix 裡那些 with、let ... in、{ ... } 到底是什麼意思?明天我們會正式認識 Nix 語言的基礎語法,讓你不只是「照抄配置」,而是能理解每一行在做什麼,並開始寫出自己的配置邏輯。
我們明天見! 🚀
📚 延伸閱讀