開機設定檔順序
可以想成兩條線:系統開機線(不管有沒有開終端機都會跑)與 shell 啟動線(只有開 Terminal / VS Code 終端機才跑)。兩者不要混在一起改。
系統開機線
flowchart TD
A[按下電源] --> B[韌體 / iBoot]
B --> C[載入 macOS 核心]
C --> D["launchd(PID 1)"]
D --> E["/System/Library/LaunchDaemons"]
E --> F["/Library/LaunchDaemons<br/>開機就跑、通常要管理員權限"]
F --> G[登入畫面]
G --> H[使用者登入]
H --> I["/Library/LaunchAgents"]
I --> J["~/Library/LaunchAgents"]
J --> K["系統設定 → 一般 → 登入項目"]
| 階段 | 位置 | 何時執行 | 典型用途 |
|---|---|---|---|
| 系統 Daemon | /System/Library/LaunchDaemons |
開機 | Apple 自己的服務,不要改 |
| 第三方 Daemon | /Library/LaunchDaemons |
開機、登入前 | 資料庫、VPN、公司管理工具 |
| 所有使用者 Agent | /Library/LaunchAgents |
任何人登入後 | 共用的輔助程式 |
| 自己的 Agent | ~/Library/LaunchAgents |
你登入後 | 個人自動啟動的 plist |
| 登入項目 | 系統設定 → 一般 → 登入項目 | 登入後 | Raycast、AltTab、通訊軟體 |
現代 App 大多註冊在「登入項目」,不一定會在 ~/Library/LaunchAgents 看到同名檔。除錯時兩個地方都要看。
舊式 /Library/StartupItems 已過時,新軟體不該再用。
不要把 PATH 寫進 LaunchDaemon 亂猜
開機服務的環境變數跟你在終端機看到的不一樣。背景程式若需要 PATH,應寫在該 plist 的 EnvironmentVariables,而不是指望 .zshrc。
登入後還會做的事
- 載入輸入法、選單列圖示。
- 啟動「允許在背景執行」的項目(系統設定同一頁)。
- 套用桌面、Dock、顯示器配置。
- 還沒讀
.zshrc。那是開 Terminal 才發生的事。
Shell 啟動線(zsh)
Catalina 之後預設 shell 是 zsh。Terminal.app、iTerm、VS Code 終端機預設開的是「登入 + 互動」shell,讀檔順序如下:
flowchart TD
A["/etc/zshenv"] --> B["~/.zshenv<br/>每次 zsh 都讀"]
B --> C{"是否為 login shell?"}
C -->|是| D["/etc/zprofile"]
D --> E["~/.zprofile"]
C -->|否| F{"是否為 interactive?"}
E --> F
F -->|是| G["/etc/zshrc"]
G --> H["~/.zshrc"]
F -->|否| I{"login?"}
H --> I
I -->|是| J["~/.zlogin"]
重點有兩個:
/etc/zprofile會跑path_helper。它讀/etc/paths與/etc/paths.d/*,再重組PATH。所以你在.zshenv裡export PATH=...的結果,常常被這一步覆蓋或重排。- Homebrew 官方建議把
brew shellenv放在~/.zprofile,就是為了接在path_helper之後。細節見 環境變數與 PATH。
非互動腳本(例如 zsh script.sh)只會讀 zshenv,不會讀 .zshrc。CI 或 launchd 跑的腳本也讀不到你在 .zshrc 寫的 alias。
關機時
zsh 若為 login shell,離開前會讀 ~/.zlogout。系統層則由 launchd 卸除 Agent / Daemon。一般使用者不必改這一段。
自己查目前狀態
# 哪些 LaunchAgents 有載入
launchctl list | head
# 這個 shell 是不是 login / interactive
echo $0
[[ -o login ]] && echo login
[[ -o interactive ]] && echo interactive
# zsh 實際讀過哪些設定檔(除錯用)
zsh -xl
zsh -xl 輸出很長,用它確認「這個檔到底有沒有被讀到」。
相關資料
man launchd、man launchctl、man zsh- 下一步:環境變數與 PATH