bash是默认的shell,有必要了解一下它不同启动方式下的配置过程。

当执行bash命令或者用户登录系统时,会陆续加载各种bash配置文件,还会设置或清空一系列变量,有时还会执行一些自定义的命令,这些行为都算是启动bash时的过程。在不同的系统中具体的逻辑还是不同的,目前只关注Ubuntu和CentOS。

启动过程有两个维度的分类方式:

  • 交互式和非交互式
    • 交互式的标准情景:输入一个命令,然后输出user@host:path$,等待用户输入;
    • 非交互式的标准情景:bash执行一个脚本,例如bash demo.sh
  • 登录和非登录:顾名思义,非登录情景可以加上--login-l选项来伪装为登录情况。

可以通过下面的方法进行判断:

  • 交互式的判断:
    • 交互式环境下的$-变量会含有字母i
    • 交互式定义了提示符$PS1,但是非交互式会清空这个变量,因此echo $PS1可以区分。
  • 登录和非登录的判断:shopt login_shell,返回onoff
1
echo $PS1;shopt login_shell

使用ssh命令时:

  • ssh远程登录:交互式、登录式;
  • ssh远程执行命令但不登录:非交互式、非登录式

使用bash命令启动shell时:

  • bash:交互式、非登录式
  • bash -l:交互式、登录式

使用bash命令执行脚本时:

  • bash demo.sh:非交互式、非登录式
  • bash -l demo.sh:非交互式、登录式

使用su命令切换用户时,加不加-有不同的效果:

  • su user2:切换到user2,打开的shell是交互式、非登录式
  • su - user2:切换到user2,打开的shell是交互式、登录式

在图形用户界面下打开终端时,默认为交互式、非登录式;但是可以在设置中改为交互式、登录式。

bash不同启动过程中涉及到的配置文件可能有

  • 系统级:
    • /etc/profile(通常在脚本中自动加载/etc/profile.d/*.sh
    • /etc/bash.bashrc
    • /etc/bashrc
  • 用户级:
    • ~/.profile
    • ~/.bash_profile
    • ~/.bash_login
    • ~/.bashrc(通常用户只需要在这里进行修改)

bash退出时还涉及~/.bash_logout等文件,这里不做讨论。此外,~/.bash_history文件记录了bash的历史命令。

对于一个交互式、登录式启动的shell,或者非交互式但是使用-l选项的情况:

  • 首先读取 /etc/profile
  • 然后依次搜索 ~/.bash_profile~/.bash_login~/.profile(在某些系统中,某个文件会自动生成,其它文件则默认不存在),仅加载其中第一个存在到且可读的文件。

使用--noprofile可以跳过这个过程。如果这里使用的是sh名称,出于兼容性考虑,只会依次加载etc/profile~/.profile

对于一个交互式、非登录式启动的shell:

  • 读取/etc/bash.bashrc~/.bashrc

对于一个非交互式、非登录式的shell(通常是执行一个脚本),不会加载类似的配置文件,但是会尝试加载$BASH_ENV这个环境变量所代表的配置文件,如果存在的话。

实践中发现,CentOS会自动生成~/.bash_profile,Ubuntu会自动生成~/.profile。两者的作用是类似的,大意是:

  • 如果存在~/.bashrc,读取这个文件;
  • 如果存在~/.local/bin这个目录,添加到PATH中。具体的措施不太一样,有的会加在PATH的头部,有的则会加在PATH的最后。

因此,在默认情况下,无论是哪一种方式启动,~/.bashrc中的内容都会被加载执行。

系统通常都会自动生成~/.bashrc文件,其中的内容却大不相同: 对于CentOS,自动生成的文件中会尝试加载/etc/bashrc文件

1
2
3
4
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi

对于Ubuntu,自动生成的文件头部有如下内容

1
2
3
4
5
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac

具体含义是:通过$-判断当前shell是不是交互式的,如果不是就直接结束,不再执行后面的命令。

上面这个例子说明,不同的系统中这些配置文件发挥的作用是很不一样的。