为什么Ubuntu的默认~/.profile文件会调用source ~/.bashrc?

这是我13.10版本附带的~/.profile文件的内容(已删除注释行):
if [ -n "$BASH_VERSION" ]; then
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

这是从Debian继承而来的,但为什么Canonical决定保留它呢?据我所知,这不是标准的*nix方式,我见过许多系统都没有这样做,所以我想他们一定有充分的理由。这可能会在运行登录shell时导致意外行为(例如通过ssh登录到机器上),用户不希望~/.bashrc被加载。
我唯一能想到的好处是不会让用户因为太多启动文件而感到困惑,并且允许他们单独编辑.bashrc并使其在任何shell类型下都能读取。然而,这个好处是可疑的,因为通常对于登录和交互式shell来说,拥有不同的设置是非常有用的,而这种做法会阻止你这样做。此外,登录shell往往不在图形环境中运行,这可能会导致错误、警告和问题(哦天哪!),具体取决于你在这些文件中设置了什么。
那么Ubuntu为什么要这样做,我漏掉了什么吗?

为什么在bash之外,-n "$BASH_VERSION"会返回true? - Elliott Frisch
@ElliottFrisch 不会这样。我的问题是为什么.profile会源码.bashrc,并非所有Linux版本都是如此,我想知道背后的原因是什么。 - terdon
debian上游似乎是这样实施的。 - Elliott Frisch
@ElliottFrisch 是的,我本以为不是这样的,所以查了一下,发现还来得及编辑我的评论。然而,在我能访问的 SuSe 系统上并非如此(尽管在 CentOS 系统上是这样的),而且据我记得,在各种系统(如 RHs、Fedoras 和旧版的 Ubuntu)上也不是这样的。所以我想知道为什么会这样。 - terdon
2个回答

这是一个来自Debian的上游决策。其背后的原因在这个非常好的wiki post中有解释,以下是其中的一部分摘录。总结起来就是“确保图形界面和非图形界面登录以相同方式工作”。

Let's take xdm as an example. pierre comes back from vacation one day and discovers that his system administrator has installed xdm on the Debian system. He logs in just fine, and xdm reads his .xsession file and runs fluxbox. Everything seems to be OK until he gets an error message in the wrong locale! Since he overrides the LANG variable in his .bash_profile, and since xdm never reads .bash_profile, his LANG variable is now set to en_US instead of fr_CA.

Now, the naive solution to this problem is that instead of launching "xterm", he could configure his window manager to launch "xterm -ls". This flag tells xterm that instead of launching a normal shell, it should launch a login shell. Under this setup, xterm spawns /bin/bash but it puts "-/bin/bash" (or maybe "-bash") in the argument vector, so bash acts like a login shell. This means that every time he opens up a new xterm, it will read /etc/profile and .bash_profile (built-in bash behavior), and then .bashrc (because .bash_profile says to do that). This may seem to work fine at first -- his dot files aren't heavy, so he doesn't even notice the delay -- but there's a more subtle problem. He also launches a web browser directly from his fluxbox menu, and the web browser inherits the LANG variable from fluxbox, which is now set to the wrong locale. So while his xterms may be fine, and anything launched from his xterms may be fine, his web browser is still giving him pages in the wrong locale.

So, what's the best solution to this problem? There really isn't a universal one. A better approach is to modify the .xsession file to look something like this:

[ -r /etc/profile ] && source /etc/profile
[ -r ~/.bash_profile ] && source ~/.bash_profile
xmodmap -e 'keysym Super_R = Multi_key'
xterm &
exec fluxbox

This causes the shell that's interpreting the .xsession script to read in /etc/profile and .bash_profile if they exist and are readable, before running xmodmap or xterm or "execing" the window manager. However, there's one potential drawback to this approach: under xdm, the shell that reads .xsession runs without a controlling terminal. If either /etc/profile or .bash_profile uses any commands that assume the presence of a terminal (such as "fortune" or "stty"), those commands may fail. This is the primary reason why xdm doesn't read those files by default. If you're going to use this approach, you must make sure that all of the commands in your "dot files" are safe to run when there's no terminal.


1我仍然认为这不是一个好主意。理想的做法是确保显示管理器会引用全局配置文件(检查)和用户的.profile文件。现在我知道为什么某些变量中有重复的路径了... - Rmano

这是Ubuntu的标准行为,~/.bashrc 是用户级别的每个交互式shell启动文件。当你打开一个终端时,实际上你启动了一个非登录、交互式shell,它会读取 ~/.bashrc~/.bashrc 的内容被导入到当前的shell环境中。这有助于获取所有用户定义的shell变量函数在当前的shell中。你也可以找到类似这样的行。
if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

为了在当前的shell环境中获得用户定义的别名是很重要的,这样可以提供良好的用户体验。例如,您可以将代理凭据存储在.bashrc中,除非它被引用,否则终端应用程序(如vizpingwgetcurllynx等)都无法正常工作。或者每次打开终端时都必须提供代理凭据。

此外,Ubuntu默认的.bashrc包含许多用户友好的别名(用于lsgrep以打印彩色输出),以及许多新的定义不同的shell变量,从而增加了用户体验。

但是,在您的ssh登录虚拟控制台登录的情况下,您基本上会得到一个交互式登录shell。在那里,shell初始化文件是~/.profile。因此,除非您引用~/.bashrc,否则您将错过.bashrc中所有这些有用的设置。这就是为什么Ubuntu默认的~/.profile会引用~/.bashrc的原因。

需要避免的情况

你不应该同时在~/.bashrc中引用~/.profile。这样会导致无限循环的情况,结果是你的终端提示符将被挂起,除非你按下Ctrl+C。在这种情况下,如果你在~/.bashrc中加入以下行:

set -x

然后你会看到当你打开一个终端时,文件描述符会停止。


谢谢,这些都是真实和有用的信息。只是它没有回答我的问题。我熟悉登录和非登录shell之间的区别。我的问题是为什么在Ubuntu系统上,.profile会调用.bashrc?SuSe Enterprise 10不会这样做,我使用过的任何Fedora版本也不会,但那是几年前的事了,我可能错了。CentOS 5.8确实会这样做。无论如何,你明白我的意思吗?这是一个设计选择,我想知道为什么要这样做。 - terdon
我并没有严格使用你提到的其他Linux发行版。你能告诉我它们如何处理在ssh会话中定义在.bashrc.bash_aliases中的别名命令的情况吗?例如,我在我的.bashrc中将ls设置为ls --color=auto的别名,并且我的.bashrc是从我的.profile中加载的。在这种情况下,我可以在ssh中使用该别名。或者我可以在ssh会话中使用代理。如果我不从.profile中加载我的.bashrc,我就会失去这些功能。我认为这一切都与更好的用户体验有关。 - sourav c.
他们不行,那些别名无法使用。是的,使用.bashrc可以解决这个问题。但它也会引起问题,我记得第一次使用具有此行为的系统时,当我在我的.bashrc中使用xset b off来禁用终端铃声时,我一直收到这些奇怪的消息,但只在X系统中才能禁用终端铃声,因此它会产生错误消息。花了我很长时间才弄清楚发生了什么,因为我没有想到在运行登录 shell 时会读取.bashrc。我只是想知道是否有关于这个问题的“官方”声明。 - terdon
我同意你的观点。我之前也遇到了一些麻烦(http://askubuntu.com/q/369830/127327)。但是只要你记住并避免一些特殊情况,它大多数时候还是很有帮助和用户友好的。不是吗 :) - sourav c.
是的,这确实有合理的原因。我只是好奇Canonical是否曾经解释过他们保持这个上游决定的理由。 - terdon
我刚刚间接地遇到了“要避免的情况”案例。.bash_rc引用了.bash_profile,而.bash_profile又引用了.profile。我不知道是什么原因导致了这种情况,因为我使用的是ZSH而不是BASH,但我怀疑Ruby RVM可能与此有关。 - karatedog