在做bash环境配置时,会遇到配置应该写到哪个文件里的问题。以centos7.5为例就有/etc/profile/etc/bashrc$HOME/.bash_profile$HOME/.profile$HOME/.bashrc这么多配置文件。本文从login shell和interactive shell两个角度交叉描述各种情况下配置文件的加载情况。参考man bash

定义

  • 登录shell的定义很简单
    第零位启动参数的首个字符为-,或启动参数中包含--login的shell。

  • 交互式shell的定义稍微复杂一点
    一个不包含“non-option arguments”并且没有-c参数的shell,它的输入和错误都连接到终端。或者一个启动参数包含-i的shell。
    这里的“non-option arguments”就是不包含在选项范围内的参数,也就是将要执行的脚本文件。比如bash SOME_SCRIPT_FILE
    -c参数启动的bash,将会启动一个bash,而后调用exec函数族执行参数中指定的程序。

获取bash

从定义可以看到,登录shell和交互式shell是从两个正交的角度描述的,因此可以取得的bash类型可以有四种

  • login and interactive shell
    既是登录shell,又是交互式shell。

    首先保证是登录shell,以下四种都是登录shell:

    • 从ssh登录得到的bash
    • 控制台登录得到的bash
    • --login-l参数运行的bash
    • su - USER_NAME得到的bash

    然后保证是交互式shell,那么在启动bash时后面不要接脚本名或-c参数既可。

  • login and non-interactive shell
    登录shell,且非交互式,比如

    • bash --login SCRIPT_NAME
    • bash --login -c BIN_FILE
  • non-login and interactive shell
    非登录shell,但是为交互式,比如
    • 直接运行bash
    • su USER_NAME,注意这里没有参数-(login参数)
    • ssh HOST COMMADN,以ssh连接服务器执行命令的情况实际会启动一个non-login and interactive的shell,具体shell类型取决于/etc/passwd文件中记录的用户shell类型,不做特殊设置一般为bash。因此如果$HOME/.bashrc文件中有向标准输出打印字符的话,可能会引起远程scp执行错误。这里的逻辑比较特殊,实际调用bash的命令为bash -c COMMAND,从其他的判断方式看应该是一个非登录且非交互式shell,但是bash源码中做了一个额外的判断,如果是由sshd或rshd启动且是一个首层shell,则会加载~/.bashrc文件。
  • non-login and non-interactive shell
    非登录shell,且非交互式。普通的非交互式shell一般就是非登录shell,注意不要增加login参数既可,比如
    • bash SCRIPT_NAME
    • bash -c BIN_FILE

配置加载

在各个固定位置的配置文件之外,有一个稍显特殊的存在,BASH_ENV环境变量。当启动一个非交互式bash时,会查找该环境变量内容,并将内容当做一个文件路径,加载该文件。

不同情况下bash加载配置文件列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
+-----------+---------------------------------------+---------------------------------------+
| | | |
| | interactive | non-interactive |
| | | |
+-----------+---------------------------------------+---------------------------------------+
| | | |
| | | |
| | /etc/profile | /etc/profile |
| | | |
| | $HOME/.bash_profile | $HOME/.bash_profile |
| login | | |
| | $HOME/.profile | $HOME/.profile |
| | (如果$HOME/.bash_profile不存在) | (如果$HOME/.bash_profile不存在) |
| | | |
| | | $BASH_ENV |
| | | |
| | | |
+-----------+---------------------------------------+---------------------------------------+
| | | |
| | | |
| | /etc/bash.bashrc | |
| non | (Ubuntu环境会加载该文件) | $BASH_ENV |
| login | | |
| | $HOME/.bashrc | |
| | | |
| | | |
+-----------+---------------------------------------+---------------------------------------+

上表结果的验证方式如下:

  • 清空系统和用户配置文件,在每个配置文件中写入各自独立的变量,不要export。
  • 配置BASH_ENV变量,export使其成为环境变量,变量内容为一个配置文件路径。
  • 启动各种类型的bash,并观察变量值。
验证准备工作(系统配置文件同样修改)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-bash-4.2$ export BASH_ENV=/home/huyu/bashenv
-bash-4.2$ cat ~/bashenv
KEY_BASH_ENV="Y"
-bash-4.2$ cat ~/.bash_profile
KEY_PER_BASH_PROFILE="Y"
-bash-4.2$ cat ~/.bashrc
KEY_PER_BASHRC="Y"
-bash-4.2$ cat t.sh
echo KEY_ETC_PROFILE "$KEY_ETC_PROFILE"
echo KEY_ETC_BASHRC "$KEY_ETC_BASHRC"
echo KEY_PER_BASH_PROFILE "$KEY_PER_BASH_PROFILE"
echo KEY_PER_BASHRC "$KEY_PER_BASHRC"
echo KEY_PER_PROFILE "$KEY_PER_PROFILE"
echo KEY_BASH_ENV "$KEY_BASH_ENV"
-bash-4.2$
login and interactive bash
1
2
3
4
5
6
7
-bash-4.2$ . t.sh
KEY_ETC_PROFILE Y
KEY_ETC_BASHRC
KEY_PER_BASH_PROFILE Y
KEY_PER_BASHRC
KEY_PER_PROFILE
KEY_BASH_ENV
non-login, interacitve bash
1
2
3
4
5
6
7
8
9
-bash-4.2$ bash
bash-4.2$ . t.sh
KEY_ETC_PROFILE
KEY_ETC_BASHRC
KEY_PER_BASH_PROFILE
KEY_PER_BASHRC Y
KEY_PER_PROFILE
KEY_BASH_ENV
bash-4.2$
login and non-interactive bash
1
2
3
4
5
6
7
8
-bash-4.2$ bash --login t.sh
KEY_ETC_PROFILE Y
KEY_ETC_BASHRC
KEY_PER_BASH_PROFILE Y
KEY_PER_BASHRC
KEY_PER_PROFILE
KEY_BASH_ENV Y
-bash-4.2$
non-login and non-interactive bash
1
2
3
4
5
6
7
8
-bash-4.2$ bash t.sh
KEY_ETC_PROFILE
KEY_ETC_BASHRC
KEY_PER_BASH_PROFILE
KEY_PER_BASHRC
KEY_PER_PROFILE
KEY_BASH_ENV Y
-bash-4.2$

配置模板

/etc/skel/目录下的文件是bash配置的模板文件,在添加新用户时,会被拷贝到新用户的HOME目录作为默认配置。

1
2
3
4
5
6
7
[huyu@centos1804 ~]$ ll /etc/skel/ -a
total 24
drwxr-xr-x. 2 root root 62 Apr 11 2018 .
drwxr-xr-x. 101 root root 8192 Aug 19 20:10 ..
-rw-r--r--. 1 root root 18 Apr 11 2018 .bash_logout
-rw-r--r--. 1 root root 193 Apr 11 2018 .bash_profile
-rw-r--r--. 1 root root 231 Apr 11 2018 .bashrc

合理配置

前文描述了login shell和interactive shell的区分,与各种情况下bash加载配置文件的区别。这里给出一个合理的配置参考。以centos7.5为例。

  • /etc/profile
    放置系统的环境变量配置
  • $HOME/.bash_profile
    放置个人的环境变量配置,并加载$HOME/.bashrc。由于登录shell不会自动加载$HOME/.bashrc,为了保证bash配置生效的一致性,这里应当主动加载$HOME/.bashrc
  • $HOME/.bashrc
    放置个人bash相关配置,并加载/etc/bashrc。这里不应该放置环境变量相关配置,因为嵌套多次运行bash时该文件会被多次加载,会导致环境变量的配置冗余。
  • /etc/bashrc
    放置系统的bash相关配置。centos7.5下这个文件不会被自动加载,因此需要被用户主动加载才能生效。

PS:

  • $HOME/.profile
    这个文件只有在$HOME/.bash_profile不存在时才会被自动加载,在使用时注意该情况既可,使用场景同$HOME/.bash_profile
  • /etc/bash.bashrc
    Ubuntu下非登录的交互式bash会自动加载该文件。使用方式可以参考centos下的/etc/bashrc,区别只是自动加载与主动加载。