Tl;dr RTFM!

昨天在折腾终端的 TERM 环境变量时总算正面遇上了之前就疑惑过的一个问题: bashrc 、 profile 、 xprofile 等等这些文件究竟是在何时、何种情况下被谁调用的呢?其实要弄清楚这个问题也很简单,阅读 Bash 的 manpage 就有很大帮助,再结合着看一些桌面管理器自带的脚本代码和做一点实验,就能弄得很明白了。这里就记录一下最终结果,略去实验过程了。

首先,有两件“通用”的事情:一、这里谈论的所有“调用”(invocation)指的事实上都是 source 而非直接运行(后者会创建一个子 shell ),也就更加不是后台运行了,所以一旦阻塞住了整个登录就会卡住;二、这些脚本都有系统级和用户级之分,除了个别特殊情况,两者等价,且先调用系统级再调用用户级(也就是用户级可以覆盖系统级)。

好了,接下来就让我们看看 man bash ,其中的 INVOCATION 章节详细说明了 bash 对这些脚本的调用过程。简单来说有三类情况(不重复、不遗漏):

  • Login shell
    不论是否是交互式的(interactive),只要 bash 以 --login 参数被启动(常见的就是 login 程序在成功登录后运行用户的默认 shell ), bash 都会并且仅会调用 profile 系的脚本外加一个 bash_login ,具体顺序是: /etc/profile~/.bash_profile~/.bash_login~/.profile不会调用 ~/.bashrc
    Login shell 在退出时还会额外调用 ~/.bash_logout
  • Non-login interactive shell
    会且仅会调用 ~/.bashrc 文件。
  • Non-login non-interactive shell
    如果 BASH_ENV 环境变量不为空(默认是空的),则会调用它指向的文件。

等一下,那有些发行版(例如 Archlinux )中带的 /etc/bash.bashrc 又是怎么回事呢?阅读一下 /etc/profile 的代码,你会发现其中调用了这个文件,从而导致了一个很坑的事情——从文件名来看像是 bashrc 的系统级文件,但事实上和它不是一回事……另外,很多发行版的 /etc/profile 还会调用 /etc/profile.d/*.sh ,从而让其他包和用户可以不用对其本身进行修改。

好了,那再让我们来看看桌面管理器又是什么情况。以 gdm 为例。

首先,图形界面的登录过程是通过 gdm 完成的,并没有调用 login ,也不会执行 bash 。 GNOME3 的流程是这样的: gdm(root) -> gdm-session-worker(root, PAM) -> gnome-session(user) -> gnome-shell(user) 。然而, profile 系列仍然会和字符终端登录一样有效。这里的“魔法”是 /etc/gdm/Xsession

阅读代码就可以知道,它依次调用了这些文件: /etc/profile~/.profile/etc/xprofile~/.xprofile 。 bashrc 仍然不会被调用( /etc/bash.bashrc 会……);不过,当你在 GNOME 中打开虚拟终端时,它就会被调用了。