macOS 登入 Shell

在其他 Unix 系統中,終端機模擬器通常以 非登入 shell 啟動。出於各種原因,macOS 預設將 所有終端機作為登入 shell。

Ghostty 尊重 macOS 的傳統,會把每個 shell 作為登入 shell 啟動。這與 macOS 上其他終端機模擬器的行為一致,其中 最主要的是預設的 Terminal.app。不過,這個行為與其他 Unix 系統不同,而這可能會讓 習慣了其他系統行為的使用者感到困惑。

為什麼使用登入 Shell

傳統上,unix shell 有兩個主要檔案,需要在使用者 能與 shell 互動之前執行:profile 檔案與 rc 檔案。 profile 檔案通常在登入時執行一次,用於為使用者 設定環境。rc 檔案在每次建立新 shell 時執行,用於 設定 shell 本身。

以 zsh 為例(macOS 10.15 起的預設 shell): zsh 使用 .zprofile 和 .zshrc 檔案。多數 Linux 系統會在使用者最初透過桌面管理器之類的途徑登入時執行 .zprofile (或類似檔案)。 這讓後續的 shell 可以繼承環境 以及 .zprofile 完成的任何設定。這裡的理念是,任何昂貴的 初始設定只需在登入時執行一次,後續 shell 可以 重複使用設定過程中的所有內容。

Note

此處以 zsh 為例,但幾乎任何 shell 替代它都能得到 相同的結果,bash 例外。Bash 只在 shell 既是互動式又非登入的情況下讀取 .bashrc。由於 macOS 從 OSX 10.2 Jaguar 開始從 tcsh 遷移到 bash,開發者可能一直忽略了 bash 的這種差異,於是把 shell 設定全部放到 .profile 中,因為 .bashrc 很少被執行,尤其是不會因為啟動新的 終端機而執行。現在 zsh 已是新的預設,.zprofile 與 .zshrc 在啟動互動式非登入 shell 時 都會被呼叫。

macOS 的不同之處在於,登入系統的 GUI 並不會 執行 .zprofile,因為它有一套自己的載入系統級全域 設定的方法。這意味著任何終端機模擬器都必須把 shell 作為登入 shell 執行,否則新的 shell 可能會出問題,因為它們會缺少 .zprofile 中的任何 設定過程。這是令人遺憾的現實,但也是合理的, 因為並不存在 .xsession 或類似的機制——.zprofile 從不 執行——無法讓使用者的終端機取得初始設定,或設定諸如 全域環境變數之類的 1。

但這不代表一切都應該直接放進 .zprofile,也不 意味著這兩個檔案總是一起被呼叫。由於 zsh 以登入 模式和互動模式啟動,.zprofile 與 .zshrc 都會在每次 建立新終端機時執行。但如果你在終端機模擬器裡面再執行一個 shell,則那只會是互動式 shell,並會失去對 在 .zprofile 中初始化的父 shell 設定的存取權。你可以驗證這一點: 在 .zprofile 裡放一個別名,啟動一個終端機實例並 執行它,然後執行 zsh,你會發現該別名已 不可用。

因此,大多數 shell 設定仍應放進 .zshrc 檔案,以便任何 shell(無論是否為終端機)都能正確初始化。這與其他 Linux 系統上 dotfiles 的寫法多少也有幾分相符。

Footnotes

  1. Why are interactive shells on OSX login shells by default? ↩