传统上,当你登录Unix系统时,系统会为你启动一个程序。这个程序是一个shell,即一个旨在启动其他程序的程序。它是一个命令行shell:你通过输入它的名字来启动另一个程序。默认的shell,即Bourne shell,当它作为登录shell被调用时,从~/.profile
读取命令。
Bash是一个类似伯恩的shell。当它作为登录shell被调用时,它从~/.bash_profile
读取命令,如果该文件不存在¹,它会尝试读取~/.profile
。
你可以在任何时候直接调用shell,例如在GUI环境下启动终端模拟器。如果shell不是登录shell,它就不会读取~/.profile
。当你以交互式shell的方式启动bash时(即不是为了运行脚本),它读取的是~/.bashrc
(除非是以登录shell的方式调用,那么它只读取~/.bash_profile
或~/.profile
。
因此:
~/.profile
是放适用于整个会话的东西的地方,比如你想在登录时启动的程序(但不是图形程序,它们会进入另一个文件),以及环境变量定义。
~/.bashrc
是放那些只适用于bash本身的东西的地方,比如别名和函数定义,shell选项,以及提示符设置。(你也可以把键绑定放在那里,但是对于bash来说,它们通常会放到~/.inputrc
中。)
~/.bash_profile
可以用来代替~/.profile
,但它只被bash读取,不被任何其他shell读取。(如果你想让你的初始化文件在多台机器上工作,并且你的登录shell不是在所有机器上都是bash的话,这主要是个问题)。如果shell是交互式的,这是一个逻辑上包含~/.bashrc
的地方。我建议在~/.bash_profile
中包含以下内容。
在现代的unices上, 有一个额外的复杂情况与~/.profile
有关. 如果你在图形环境中登录(也就是说,如果你输入密码的程序是在图形模式下运行的),你不会自动得到一个读取~/.profile
的登录外壳。根据图形登录程序,根据你之后运行的窗口管理器或桌面环境,以及根据你的发行版如何配置这些程序,你的~/.profile
可能被读取,也可能不被读取。如果没有,通常有另一个地方,你可以定义环境变量和程序,当你登录时启动,但不幸的是没有标准的位置。
注意,你可能会在这里和那里看到一些建议,要么把环境变量定义放在~/.bashrc
中,要么总是在终端中启动登录外壳。这两个都是坏主意。这些想法中最常见的问题是,你的环境变量只能在通过终端启动的程序中设置,而不是在用图标、菜单或键盘快捷键直接启动的程序中设置。
¹ 为了完整,根据要求:如果.bash_profile
不存在,bash也会先尝试.bash_login
,然后再回落到.profile
。随意忘记它的存在。
从这个短文
根据bash手册页面,.bash_profile是为登录外壳执行的,而.bashrc是为交互式非登录外壳执行的。
*什么是登录或非登录shell? *
当你通过控制台登录(例如:输入用户名和密码)时,无论是开机时坐在机器上,还是通过ssh远程登录:.bash/_profile会在初始命令提示符之前被执行来配置。
但是,如果你已经登录到你的机器,并在Gnome或KDE中打开了一个新的终端窗口(xterm),那么.bashrc就会在窗口命令提示符之前被执行。.bashrc也会在你通过在终端中输入/bin/bash来启动一个新的bash实例时被运行。
在以前,当伪TTY不是伪的,而是真正的,好吧,打字的时候,UNIX是通过调制解调器访问的,速度很慢,你可以看到每个字母都被打印到屏幕上,效率是最重要的。为了提高效率,你有一个主登录窗口的概念,以及其他任何你用来实际工作的窗口。在你的主窗口中,你希望收到任何新邮件的通知,可能会在后台运行一些其他程序。
为了支持这一点,shell专门在 “登录shell "上采购了一个文件.profile
。这将做特殊的,一旦会话设置。Bash在某种程度上扩展了这一点,先看.bash_profile,再看.profile,这样你就可以把bash专用的东西放在里面(这样就不会把Bourne shell等也看.profile的东西搞坏)。其他的shell,非login的,只需要把rc文件,.bashrc(或.kshrc等)作为源文件。
这个现在有点不合时宜了。你不像登录gui窗口管理器那样登录主shell。主窗口和其他窗口没有任何区别。
我的建议是–不要担心这种差异,它是基于一种旧的使用unix的风格。在你的文件中消除这种差异。.bash_profile的全部内容应该是。
[-f $HOME/.bashrc] && . $HOME/.bashrc
把所有你想设置的东西都放在.bashrc
记住.bashrc是所有shell的源文件,不管是交互式的还是非交互式的。你可以把这段代码放在.bashrc的顶部,以短路非交互式shell的资源:
[[$- != *i*]] && return
。
看看这篇【ShreevatsaR的优秀博文】(http://shreevatsa.wordpress.com/2008/03/30/zshbash-startup-files-loading-order-bashrc-zshrc-etc/)。这是一个摘录,但请去看博文,它包括了一个术语的解释,比如 “登录shell",一个流程图,以及一个类似的Zsh表。
对于Bash,它们的工作原理如下。往下读相应的列。先执行A,再执行B,再执行C,等等。B1, B2, B3意味着它只执行找到的第一个文件。
+----------------+-----------+-----------+------+
| |Interactive|Interactive|Script|
| |login |non-login | |
+----------------+-----------+-----------+------+
|/etc/profile | A | | |
+----------------+-----------+-----------+------+
|/etc/bash.bashrc| | A | |
+----------------+-----------+-----------+------+
|~/.bashrc | | B | |
+----------------+-----------+-----------+------+
|~/.bash_profile | B1 | | |
+----------------+-----------+-----------+------+
|~/.bash_login | B2 | | |
+----------------+-----------+-----------+------+
|~/.profile | B3 | | |
+----------------+-----------+-----------+------+
|BASH_ENV | | | A |
+----------------+-----------+-----------+------+
| | | | |
+----------------+-----------+-----------+------+
| | | | |
+----------------+-----------+-----------+------+
|~/.bash_logout | C | | |
+----------------+-----------+-----------+------+
**
# For BASH: Read down the appropriate column. Executes A, then B, then C, etc.
# The B1, B2, B3 means it executes only the first of those files found. (A)
# or (B2) means it is normally sourced by (read by and included in) the
# primary file, in this case A or B2.
#
# +---------------------------------+-------+-----+------------+
# | | Interactive | non-Inter. |
# +---------------------------------+-------+-----+------------+
# | | login | non-login |
# +---------------------------------+-------+-----+------------+
# | | | | |
# | ALL USERS: | | | |
# +---------------------------------+-------+-----+------------+
# |BASH_ENV | | | A | not interactive or login
# | | | | |
# +---------------------------------+-------+-----+------------+
# |/etc/profile | A | | | set PATH & PS1, & call following:
# +---------------------------------+-------+-----+------------+
# |/etc/bash.bashrc | (A) | A | | Better PS1 + command-not-found
# +---------------------------------+-------+-----+------------+
# |/etc/profile.d/bash_completion.sh| (A) | | |
# +---------------------------------+-------+-----+------------+
# |/etc/profile.d/vte-2.91.sh | (A) | | | Virt. Terminal Emulator
# |/etc/profile.d/vte.sh | (A) | | |
# +---------------------------------+-------+-----+------------+
# | | | | |
# | A SPECIFIC USER: | | | |
# +---------------------------------+-------+-----+------------+
# |~/.bash_profile (bash only) | B1 | | | (doesn't currently exist)
# +---------------------------------+-------+-----+------------+
# |~/.bash_login (bash only) | B2 | | | (didn't exist) **
# +---------------------------------+-------+-----+------------+
# |~/.profile (all shells) | B3 | | | (doesn't currently exist)
# +---------------------------------+-------+-----+------------+
# |~/.bashrc (bash only) | (B2) | B | | colorizes bash: su=red, other_users=green
# +---------------------------------+-------+-----+------------+
# | | | | |
# +---------------------------------+-------+-----+------------+
# |~/.bash_logout | C | | |
# +---------------------------------+-------+-----+------------+
#
# ** (sources !/.bashrc to colorize login, for when booting into non-gui)
在 Flimm 的回答的基础上,我在我的 Debian /etc/profile 的头部插入了这个新的注释,(你可能需要根据你的发行版调整它。):
# TIP: SEE TABLE in /etc/profile of BASH SETUP FILES AND THEIR LOAD SEQUENCE
然后在每个其他设置文件的头部插入了这个注释来参考它。
0x1&
值得注意的是,Debian的/etc/profile默认是包括/etc/bash.bashrc的(当/etc/bash.bashrc存在时)。所以登录脚本会同时读取两个/etc文件,而非登录脚本只读取bash.bashrc。
另外需要注意的是,/etc/bash.bashrc在不交互式运行时,被设置为什么都不做。所以这两个文件只适用于交互式脚本。
bash的配置逻辑本身并不复杂,在本页的其他答案中,在serverfault和许多博客中都有解释。然而,问题是_Linux发行版对bash做了什么,我的意思是他们默认配置bash的复杂和各种方式。http://mywiki.wooledge.org/DotFiles 简单地提到了一些这些怪癖。这是Fedora 29上的一个跟踪示例,它显示了在一个非常简单的情况下,哪些文件是其他文件的来源,以及顺序:远程连接ssh,然后启动另一个子shell:
ssh fedora29
└─ -bash # login shell
├── /etc/profile
| ├─ /etc/profile.d/*.sh
| ├─ /etc/profile.d/sh.local
| └─ /etc/bashrc
├── ~/.bash_profile
| └─ ~/.bashrc
| └─ /etc/bashrc
|
|
└─ $ bash # non-login shell
└─ ~/.bashrc
└─ /etc/bashrc
└─ /etc/profile.d/*.sh
Fedora最复杂的逻辑是在/etc/bashrc
。如上所述/etc/bashrc
是一个bash本身不知道的文件,我是说不直接知道。Fedora的/etc/bashrc
测试是否。
-是否被登录的shell获取, -是否被交互式shell获取, -是否已经被获取
…… 然后根据这些情况做完全不同的事情。
如果你认为能记住上面的图,那么太糟糕了,因为还远远不够:这个图只是描述了一种情况,在运行非交互式脚本或启动图形会话时,会发生稍微不同的事情。我已经省略了~/.profile
。我省略了bash_completion
脚本。出于向后兼容的原因,调用bash为/bin/sh
而不是/bin/bash
会改变其行为。那zsh和其他shell呢?当然,不同的Linux发行版做的事情是不同的,比如Debian和Ubuntu就有一个非标准版本的bash,它有Debian特有的自定义功能。它主要是寻找一个不寻常的文件。/etc/bash.bashrc
. 即使你坚持使用单一的Linux发行版,它也可能会随着时间的推移而变化。等等:我们还没有接触到macOS、FreeBSD、…… 最后,让我们为用户想一想,他们的管理员用更有创意的方式配置了他们必须使用的系统。
正如关于这个话题的永无止境的讨论流所表明的那样,这是一个失败的原因。只要你只是想添加新的值,一些 “试错 "往往就足够了。当你想在一个(用户)文件中修改另一个(在/etc中)已经定义的东西时,真正的乐趣才开始。那么就要准备好花一些时间来设计一个永远无法移植的解决方案。
为了最后一点乐趣,这里是2019年6月在Clear Linux上相同的简单方案的 "源图":
ssh clearlinux
└─ -bash # login shell
├── /usr/share/defaults/etc/profile
| ├─ /usr/share/defaults/etc/profile.d/*
| ├─ /etc/profile.d/*
| └─ /etc/profile
├── ~/.bash_profile
|
|
└─ $ bash # non-login shell
├─ /usr/share/defaults/etc/bash.bashrc
| ├─ /usr/share/defaults/etc/profile
| | ├─ /usr/share/defaults/etc/profile.d/*
| | ├─ /etc/profile.d/*
| | └─ /etc/profile
| └─ /etc/profile
└─ ~/.bashrc
```。