macOS defaults 備份別踩坑:為什麼 5.3MB 的 plist 不如 130 行的 shell script
本篇是「一鍵搞定新 Mac」系列的第 9 / 9 篇。你可以從系列總覽開始閱讀,也可以直接接著看本文。
最近在整理我的 dotfiles,準備讓新電腦能「一鍵安裝」。用的是 chezmoi 管設定檔、Brewfile 管軟體安裝,整套流程已經跑得很順了。
但有一件事我一直沒搞定:macOS 的系統偏好設定。
每次換電腦,Dock 要重新設、Finder 要重新調、鍵盤重複速度要重新改⋯⋯這些瑣碎的設定加起來,大概要花半小時到一小時。
所以我想:不如用 defaults export 把整台電腦的設定匯出成 plist,跟 dotfiles 放在一起不就好了?
背景
一個完整的 macOS 開發環境大概有這三層:
| 層級 | 內容 | 負責工具 |
|---|---|---|
| 軟體安裝 | CLI 工具、桌面 App | Homebrew (Brewfile) |
| 系統設定 | dotfiles、shell config、Git config | chezmoi |
| macOS 偏好設定 | Dock、Finder、鍵盤速度⋯ | ??? |
前兩層我都解決了,第三層一直是空的。defaults export 看起來就是那個完美答案。
發現過程
我跑了這個指令把全部 domain 匯出:
# 把所有 domain 的 user defaults 一次 dump 出來
# 注意:defaults export -g 只會匯出 NSGlobalDomain「一個」domain,不是全部;
# 要看到全部 domain 得用無參數的 defaults read(或對 defaults domains 列出的每個 domain 逐一 export)
defaults read > ~/macos-defaults-backup.txt
得到一個 5.3MB 的備份檔。
把它加進 dotfiles repo 之前,我先用 Claude Code 分析了一下內容。這一看嚇了一跳。
裡面到底有什麼?
這個 plist 包含 1,363 個 domain,大致分成四類:
1. 系統全域設定(你真正想要的)
Apple Global Domain → AppleInterfaceStyle = Dark
→ KeyRepeat = 2
→ InitialKeyRepeat = 15
Dock 大小、鍵盤速度、深色模式之類的設定。大概佔不到 5%。
2. Apple 原生 App 設定(部分有用)
com.apple.dock → autohide = true, tilesize = 48
com.apple.finder → ShowPathbar = true
Finder、Dock、Safari 的開發者工具⋯⋯這些也是你會想帶到新機的設定。
3. 第三方 App 的私有資料(大量雜訊)
Microsoft Edge 的 A/B test flight flags(上千個實驗旗標)、Mixpanel tracking tokens、各種 app 的 session 狀態⋯⋯這些佔了整個檔案 90% 以上的體積,而且搬到新機器上完全沒意義。
4. 機敏資料(不該公開的東西)
這是最嚇人的部分:
| 資料類型 | 內容範例 |
|---|---|
| 廣告 ID | advertisingId = 112e622f... |
| 搜尋 client ID | searchClientId = 30754106... |
| GPS 座標 | location = "339550.0&5376927.4" |
| Session tokens | 多個 App 的登入 token |
| iCloud sync tokens | Apple 服務的同步 token |
如果我就這樣 push 到 public GitHub repo⋯⋯嗯,不敢想。
具體數據 / 結果
| 方案 | 檔案大小 | Domain 數 | 可讀性 | 隱私風險 |
|---|---|---|---|---|
defaults export plist | 5.3 MB | 1,363 | 極差(二進位 + 雜訊) | 高(含 GPS、token) |
手寫 defaults.sh | 3 KB | ~15 | 極佳(每行有註解) | 零 |
5.3MB 的全量匯出,不如 130 行的手寫 script。
我的 macos/defaults.sh 長這樣(節錄):
#!/bin/bash
# 加快鍵盤重複速度
defaults write NSGlobalDomain KeyRepeat -int 2
defaults write NSGlobalDomain InitialKeyRepeat -int 15
# 停用自動修正(寫程式不需要)
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
# 自動隱藏 Dock
defaults write com.apple.dock autohide -bool true
defaults write com.apple.dock tilesize -int 48
# 顯示隱藏檔案
defaults write com.apple.finder AppleShowAllFiles -bool true
# 顯示路徑列
defaults write com.apple.finder ShowPathbar -bool true
# 重啟相關服務
killall Dock 2>/dev/null || true
killall Finder 2>/dev/null || true
每一行都看得懂在幹嘛,而且只設定我「真正在意」的東西。
那原始 plist 要怎麼用?
我把它留在 repo 裡,但標記為「查閱用參考」而不是「直接匯入用」。如果換了新電腦後發現少了什麼設定,可以在 plist 裡搜尋對應的 key,然後手動加到 defaults.sh。
# 在 plist 裡找特定設定
grep -i "screenshot" ~/macos-defaults-backup.plist
同時把它加進 .gitignore,不 commit 到 public repo:
echo "macos-defaults-backup.plist" >> .gitignore
反思
技術面
defaults export 就像 mysqldump 不加 --where——它忠實地把所有東西都倒出來,但大部分你不需要,有些還有害。
正確做法是手動挑選你在意的設定,寫成一個 shell script。好處:
- 可讀:每行有註解,未來的自己看得懂在幹嘛
- 可控:只動你確定知道效果的設定,不會有意外
- 安全:不會意外洩漏隱私資料
- 可移植:不同 macOS 版本之間相容性更好(全量 plist 有時候會帶入跟版本綁定的設定)
如果想參考別人精選的設定,mathiasbynens/dotfiles 的 .macos 是業界常用的參考範本。
心態面
工程師很容易有「既然能自動化,就全部自動化」的衝動。但有些事情,精心挑選比全量匯出更有價值。
dotfiles 的精髓不是「把舊電腦複製一份」,而是「把你的偏好用程式碼表達出來」。就像你不會把整個 node_modules commit 進 repo,你也不該把整台電腦的 defaults 無腦倒出來。
有趣發現
- Microsoft Edge 光是 A/B test 的 flight flags 就是一整面字串,佔了 plist 裡面巨大的篇幅
- 我發現自己裝了一個叫
AnswerDesign.EyeLoveU的番茄鐘 App,設定是 work 20min / rest 5min,完全不記得什麼時候裝的 - plist 裡面有
com.bobo52310.notionboard.settings——是我自己開發的 App,看到自己的 bundle ID 出現在系統 defaults 裡面,有種奇妙的感覺