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 从不 运行,因此无法让用户的终端访问初始设置,或设置.nan 像全局环境变量之类的 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? ↩