Loading...

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-storenixos-version

學完今天的內容,你就能自信地操作 NixOS,而不是只會那一招 nixos-rebuild switch


nixos-rebuild 完全解析

nixos-rebuild 是 NixOS 上最重要的指令,沒有之一。每次你修改了 configuration.nix,都需要透過它來讓變更生效。但「生效」這件事,其實有好幾種模式。

五種子指令一覽

sudo nixos-rebuild <子指>
子指令行為適用情境
switchBuild → 切換到新 generation → 重啟受影響的 service日常使用,最常見
bootBuild → 設為下次開機的 generation,但不立即切換想在下次重開機時才套用變更
testBuild → 立即切換,但不寫入 bootloader想先測試配置,重開機後會回到原本的 generation
build只 build,不切換也不寫入 bootloader想確認配置能不能成功 build
dry-build只做 evaluation,列出「會 build 什麼」,但不實際 build快速預覽變更範圍

讓我們逐一拆解。

switch — 你的日常主力

sudo nixos-rebuild switch

這是最常用的指令。它會:

  1. 評估(evaluate)/etc/nixos/configuration.nix
  2. 建置(build)所有需要的 derivation
  3. 建立一個新的 generation
  4. 將系統切換到新的 generation
  5. 重新啟動受影響的 systemd service
  6. 更新 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 快速回滾

前面提到的回滾機制,就是搭配 switchboot 使用:

# 回滾到上一個 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-envimperative 的——它讓你像用 apt install 一樣直接安裝套件,但這些操作不會反映在 configuration.nix 裡。這就破壞了 NixOS 最核心的 declarative 精神:你的系統狀態應該完全由配置檔定義。

話雖如此,你還是需要認識它,因為:

  1. 很多教學文章和論壇回答會提到 nix-env
  2. 有時候你就是想臨時裝個工具試用,不想改 configuration.nix
  3. 理解它能幫助你更深入理解 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.nixenvironment.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 的縮寫,它會:

  1. 刪除所有舊的 system generation(除了目前啟用的)
  2. 刪除所有舊的 user profile generation
  3. 執行 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系統配置的核心執行器,有 switchboottestbuilddry-build 五種模式
nix-env使用者層級的 imperative 套件管理,認識即可,日常建議用 configuration.nixnix-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 裡那些 withlet ... in{ ... } 到底是什麼意思?明天我們會正式認識 Nix 語言的基礎語法,讓你不只是「照抄配置」,而是能理解每一行在做什麼,並開始寫出自己的配置邏輯。

我們明天見! 🚀


📚 延伸閱讀