为什么默认情况下 OSX 登录 shell 上有交互式 shell?

ter*_*don 50 osx bash

在 Linux 中,据我所知,在所有 Unix 系统中,终端模拟器默认运行交互式、非登录 shell。这意味着,对于 bash,启动的 shell 将:

当启动非登录 shell 的交互式 shell 时,bash 会从/etc/bash.bashrc和读取并执行命令~/.bashrc(如果这些文件存在)。这可以通过使用--norc 选项来禁止 。

--rcfile 文件选项将强制bash读取和文件,而不是执行命令/etc/bash.bashrc~/.bashrc

对于登录 shell:

当 bash 作为交互式登录 shell 或作为具有--login选项的非交互式 shell 调用时,它首先从文件中读取并执行命令/etc/profile(如果该文件存在)。读取该文件后,它会按该顺序查找~/.bash_profile~/.bash_login、 和~/.profile,并从第一个存在且可读的命令中读取和执行命令。

--noprofile当 shell 启动时可以使用该选项来禁止这种行为。

在OSX上,但是,默认壳(这是bash)的开始在缺省终端(Terminal.app)实际上源~/.bash_profile~.profile等等。换句话说,它的作用就像一个登录shell。

主要问题:为什么默认的交互式 shell 是 OSX 上的登录 shell?为什么 OSX 选择这样做?这意味着所有提及更改内容的基于 shell 的内容的说明/教程~/.bashrc在 OSX 上都将失败,反之亦然~/.profile。尽管如此,尽管可以对 Apple 提出许多指控,但雇用无能或愚蠢的开发人员并不是其中之一。据推测,他们有充分的理由这样做,那为什么呢?

子问题:Terminal.app 是否真的运行了一个交互式登录 shell 或者他们是否改变了 bash 的行为?这是特定于 Terminal.app 还是独立于终端模拟器?

Ilm*_*nen 43

它就是这样认为的工作是,在点当你得到一个shell提示符下,双方.profile.bashrc已运行。您如何达到这一点的具体细节是次要的,但是如果根本没有运行任何一个文件,那么您将拥有一个设置不完整的外壳。

Linux(和其他基于 X 的系统)上的终端模拟器不需要自己运行的原因.profile是它通常在您登录到 X 时已经运行了。 中的设置.profile应该是那种可以由子进程继承,因此只要在您登录时执行一次(例如 via .Xsession),任何进一步的子shell 都不需要重新运行它。

正如Alan Shutko 链接的Debian wiki 页面所解释的那样:

“那么为什么是.bashrc一个单独的文件.bash_profile?这样做主要是出于历史原因,当时机器与今天的工作站相比非常慢。处理命令.profile.bash_profile可能需要相当长的时间,尤其是在有大量工作的机器上必须由外部命令(预 bash)完成。因此,将创建可以传递给子进程的环境变量的困难的初始设置命令放入.bash_profile. 未继承的瞬态设置和别名在.bashrc这样他们可以通过每个子shell重读“。

所有相同的规则也适用于 OSX,除了一件事——OSX GUI.profile在您登录时不会运行,这显然是因为它有自己的加载全局设置的方法。但这意味着 OSX的终端模拟器确实需要运行.profile(通过告诉 shell 它启动它是一个登录 shell),否则你最终会得到一个可能瘫痪的 shell。


现在,bash 有一个愚蠢的特性,大多数其他 shell 都不共享,.bashrc如果它作为登录 shell 启动,它将不会自动运行。标准的解决方法是在 中包含类似以下命令的内容.bash_profile

[[ -e ~/.profile ]] && source ~/.profile    # load generic profile settings
[[ -e ~/.bashrc  ]] && source ~/.bashrc     # load aliases etc.
Run Code Online (Sandbox Code Playgroud)

或者,也可以完全没有.bash_profile,只需在通用.profile文件中包含一些特定于 bash 的代码即可在.bashrc需要时运行。

如果 OSX 默认.bash_profile.profile 不这样做,那么这可以说是一个错误。在任何情况下,正确的解决方法是简单地将这些行添加到.bash_profile.


编辑: 正如 strugee 指出的那样,OSX 上的默认 shell 曾经是 tcsh,在这方面它的行为更加理智:当作为交互式登录 shell 运行时,tcsh 会自动读取.profile .tcshrc/ .cshrc,因此不需要任何变通方法,例如.bash_profile技巧如上所示。

基于此,我 99% 肯定 OSX 未能提供适当的默认值.bash_profile是因为当他们从 tcsh 切换到 bash 时,Apple 的人们根本没有注意到 bash 启动行为中的这个小问题。使用 tcsh,不需要这样的技巧——从 OSX 终端仿真器 Just Plain Works 将 tcsh 作为登录 shell 启动,并在没有这些kluges 的情况下做正确的事情。

  • 不,问题是他们在终端模拟器中启动登录 shell。点文件是默认的 bash 行为,启动登录 shell 将读取配置文件等,而不是 bashrc 等。问题是为什么运行登录 shell 而不是非登录 shell。 (3认同)
  • 谢谢,这些我都知道了。我的问题是_为什么_OSX 选择以这样的方式进行设置以使“.bashrc”无关?为什么他们选择让所有 shell 都成为登录 shell?据我所知,只有你的最后一句话解决了这个问题,并且只是说这是一个错误。 (2认同)
  • 是的,我和 Alan 都解释过,这是因为与 Linux 不同,OSX 在用户登录 GUI 时不会执行 `.profile`,所以他们必须稍后执行它来获取环境变量,例如 `$PATH`,通常在`.profile`中设置,正确配置。事实上,作为副作用,这会导致 `.bashrc` 无法被获取是一个错误;您可以争论它是 bash 中的错误还是 OSX 中的错误,但这并没有改变这样一个事实,即*正确* 行为将确保来自`.profile` 的环境变量和来自`.profile` 的 bash 配置设置。 bashrc` 已加载。 (2认同)
  • 使用 .bashrc 源 .profile 是一个坏主意,因为它会导致每个子 shell 重新运行 .profile 。如果不出意外的话,这会导致常见的“.profile”习惯用法,例如“export PATH =”$HOME/bin:$PATH”,继续在“$PATH”前面添加冗余条目。拥有 `.profile` 源 `.bashrc` 更有意义,但只有在检查它运行的 shell 实际上是 bash 之后才有意义。正如我上面所建议的,让“.bash_profile”同时获取“.profile”*和*“.bashrc”,在我看来是最明智的选择。 (2认同)
  • 我说的是“他们为什么使用登录外壳?”的答案。是“因为他们需要加载`.profile`”,而答案是“他们为什么不从`.profile` 中获取`.bashrc` 呢?” 是*“因为这是一个错误!”* 说真的,这不可能是故意的决定;这只是他们忽略的东西,大概是因为,在 Mac 生态系统中,shell 是大多数用户不应该处理的二等公民。(附注。另见 [strugee's answer](http://unix.stackexchange.com/a/119635) 以获取历史解释;几乎可以肯定这是从 tcsh 切换到 bash 的回归。) (2认同)
  • @huangzonghao:我假设你使用的是某种类型的 Linux 系统?当您登录时,您的 GUI 登录管理器可能已设置为源“/etc/profile”和“~/.profile”;但由于它不是 bash,因此它不会来源 `~/.bash_profile`,因为这纯粹是 bash 的事情。当您通过 Ctrl+Alt+1 登录时,您将直接登录到 shell,它将负责设置配置文件;如果您的登录 shell 是 bash,则意味着如果存在“~/.bash_profile”,它将获取“~/.bash_profile”(否则将尝试获取“~/.profile”)。 (2认同)

Ala*_*tko 15

X 终端应用程序默认运行非登录 shell 的主要原因是,在开始时,您的 .Xsession 会运行 .profile 来设置您的初始登录项。然后,因为这一切都已经设置好了,终端应用程序不需要运行它,他们可以运行 .bashrc。关于为什么这很重要的讨论在https://wiki.debian.org/DotFiles

我们以 xdm 为例。pierre 有一天休假回来,发现他的系统管理员在 Debian 系统上安装了 xdm。他登录得很好,xdm 读取了他的 .xsession 文件并运行了fluxbox。一切似乎都很好,直到他在错误的语言环境中收到错误消息!由于他覆盖了 .bash_profile 中的 LANG 变量,并且 xdm 从不读取 .bash_profile,因此他的 LANG 变量现在设置为 en_US 而不是 fr_CA。

现在,这个问题的天真解决方案是,他可以配置他的窗口管理器来启动“xterm -ls”,而不是启动“xterm”。这个标志告诉 xterm 它应该启动一个登录 shell 而不是启动一个普通的 shell。在这种设置下,xterm 生成 /bin/bash 但它把“-/bin/bash”(或者可能是“-bash”)放在参数向量中,所以 bash 就像一个登录 shell。这意味着每次他打开一个新的 xterm 时,它都会读取 /etc/profile 和 .bash_profile(内置 bash 行为),然后是 .bashrc(因为 .bash_profile 说要这样做)。起初这似乎工作得很好——他的点文件并不重,所以他甚至没有注意到延迟——但还有一个更微妙的问题。他还直接从他的 Fluxbox 菜单启动了一个网络浏览器,并且 Web 浏览器继承了 Fluxbox 的 LANG 变量,该变量现在设置为错误的语言环境。因此,尽管他的 xterms 可能没问题,并且从他的 xterms 启动的任何内容都可能没问题,但他的 Web 浏览器仍然为他提供了错误区域设置的页面。

在 OS X 上,用户环境不是由一堆 shell 脚本启动的,并且 launchd 不会在任何时候提供 .profile。(这有点可惜,因为这意味着设置环境变量要烦人得多,但这就是生活。)既然没有,那么它什么时候运行 .profile? 当您通过 ssh 登录时?这似乎毫无意义,因为许多盒子永远不会成为 ssh 的目标。不妨让终端默认运行登录 shell,以便 .profile 将在某个时候运行。

那么 .bashrc 呢?没用吗?不。它仍然具有它在 VT100 时代的用途。它用于打开终端窗口以外的任何时间打开外壳。因此,如果您使用 Emacs 或 vi,或者您使用 su 用户。

  • 您引用的 Debian 页面解释了为什么 Debian 的“.profile”源“.bashrc”,而不是为什么 OSX 决定默认让所有 shell 登录 shell。实际上,您正在回答[我的另一个问题](http://askubuntu.com/q/432508/85695),谢谢!然而,据我所知,你的答案并没有解释 OSX 的选择,而且 Debian 的引用在这里完全不相关(如果我错过了重点,请告诉我)。OSX 方式使 `.bashrc` 等无用,并且不会使 `.profile` 变得更有用。 (2认同)

str*_*gee 5

我不知道他们为什么会这样做。但是,这是我的猜测。

首先,值得注意的是,在 GNU/Linux 系统上,您当然可以切换到 vt1、vt2 等。您会在那里获得登录 shell。在 OS X 系统上,没有等价物。访问 UNIX 基础的唯一方法是通过终端仿真器或通过单用户模式(免责声明:我从未真正使用过单用户模式;它是命令行驱动的 IIRC,但我可能错了)。因此,在 OS X 中,模拟器中的任何默认设置都是整个系统的默认设置。

现在,为什么要使默认登录 shell ?我能想到这样做的几个原因(阅读:不是很多)。

  • 如果您通过 SSH 进入盒子,它会提供一致的用户体验。(对于 OS X 的服务器版尤其重要 - 大概如果您运行的是 OS X 服务器,那么您就是新手。)
  • OS X 的默认 shell 曾经是tcsh. 这是您所能得到的最疯狂的猜测,但可能是tcsh在作为登录 shell 运行时通常会做一些事情,并且历史模式卡住了。(不过,我对此表示怀疑 - 也许一位年长的常客可以告诉我们。)
  • “我们是 Apple。我们是地球上最大的 UNIX 发行版的供应商。不管我们的理由多么微不足道;如果我们做出决定,您的工具必​​须处理它。”

老实说,我已经使用 Darwin 大约 6 年了,我无法正确回答这个问题。这对我来说也没有意义。

要回答您的子问题,bash没有打补丁或任何东西(至少为此)。默认终端模拟器默认运行登录 shell,大概 iTerm 会复制它。

  • @IlmariKaronen 你的意思是(这里和那里)(https://unix.stackexchange.com/a/119675/11938)) tcsh 源 *`.login`* 和 `.tcshrc`/`.cshrc` 吗?tcsh 获取 `.profile` 是没有意义的;它通常包含“tcsh”不接受的具有“sh”语法的命令。我没有 macOS,但我在 Ubuntu 16.04 上将 `/bin/tcsh` 作为我的登录 shell。`.profile` 没有来源。[tcsh(1)](http://manpages.ubuntu.com/manpages/xenial/en/man1/tcsh.1.html) 没有提到该文件,这个 [tcsh(1)](https: //developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/tcsh.1.html)。 (2认同)