liaijie@Silence ~ cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.
/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
使用cat /etc/shells
可以看到本机有多种shell
liaijie@Silence ~ echo $SHELL
/bin/zsh
使用echo $SHELL
打印输出当前使用的命令行工具,可以看到我这里使用的是zsh
使用chsh
命令切换shell
liaijie@Silence ~ chsh -s /bin/bash
Changing shell for liaijie.
Password for liaijie:
再次查看当前shell
Silence:~ liaijie$ echo $SHELL
/bin/bash
(以上操作环境为macOS
,这里只是为了演示,我最后又切回了zsh
)
需要登录的shell(login shell): 需要用户名、密码登录后才能进入的shell,例如远程终端工具(secureCRT、xshell、putty)、开机shell登录、ssh登录、通过su - username
切换到新用户
不需要登录的shell(non-login shell):在图形界面中启动一个终端shell、在login shell
终端输入bash
打开一个新的shell、通过su username
切换到新用户
Su
是switch user
或set user id
的一个缩写
su
只能获得root的执行权限,不能获得环境变量
su -
能切换到root并获得root的环境变量及执行权限
bash test.sh
这种形式执行脚本文件,它并不与用户交互,而是一次性执行脚本 当脚本执行完毕 shell即终止。通过echo $-
可以查看当前是否为交互式shell,包含i
即为交互式,反之则为非交互式
直接打开mac的终端输入一下命令
liaijie@Silence ~ echo $-
569JNRXZghiklms
可以看到包含i
,即为交互式sehll
编写一个.sh
脚本,并在脚本中输出$-
#!/bin/zsh
echo $-
运行
zliaijie@Silence ~ zsh 01.sh
569X
可以看到不包含i
,即在运行脚本时为非交互式shell
在一般的 linux
或者 unix
(macOS
也是unix
内核)系统中, 都可以通过编辑 bashrc
和 profile
来设置用户的工作环境, 很多文章对于 profile
和 bashrc
也都有使用, 但究竟每个文件都有什么作用和该如何使用呢?
我们一般叫环境配置文件
,bash
手册中把这类文件成为startup文件
,可以想象成是一个脚本,每次启动的时候都会初始化一遍,当然这不是bash
才独有的
Linux shell
是用户与Linux
系统进行交互的媒介,而bash
作为目前Linux
系统中最常用的shell,它支持的startup
文件也并不单一,甚至让人感到费解。本文以CentOS 7
系统为例,对bash
的startup
文件进行一些必要的梳理和总结。
(1)先来看看bash手册上的描述
/etc/profile
The systemwide initialization file, executed for login shells。系统初始化文件,在login shells时执行
/etc/bash.bash_logout
The systemwide login shell cleanup file, executed when a login shell exits。系统的登录shell清理文件,当一个登录shell退出时执行。
~/.bash_profile
The personal initialization file, executed for login shells。个人初始化文件,为登录shell执行。
~/.bashrc
The individual per-interactive-shell startup file。每个交互式shell启动文件。
~/.bash_logout
The individual login shell cleanup file, executed when a login shell exits。单个登录shell清理文件,当一个登录shell退出时执行。
此外,bash还支持~/.bash_login
和~/.profile
文件,作为对其他shell的兼容,他们与~/.bash_profile
文件的作用是相同的。
备注:Debian
系统会使用~/.profile
文件取代~/.bash_profile
文件,相关细节上也会和CentOS略有不同。
通过名字的不同,我们可以直观地将startup文件分为“profile”
与“rc”
两个系列,其实他们的功能都很类似,但是使用的场景不同,这也是大家最容易忽略的地方。
所谓的不同场景,其实就是shell的运行模式。我们知道运行中的bash有“交互”
和“登陆”
两种属性,而执行“profile”系列还是“rc”系列,就与shell的这两个属性有关。
原理上讲,“登陆shell”
启动时会加载“profile”
系列的startup文件,而“交互式非登陆shell”
启动时会加载“rc”
系列的startup文件
根据bash手册上的描述:
When bash is invoked as an interactive login shell, or as a non-interactive shell with the –login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The –noprofile option may be used when the shell is started to inhibit this behavior.
When a login shell exits, bash reads and executes commands from the files ~/.bash_logout and /etc/bash.bash_logout, if the files exists.
翻译成中文为:
当bash被作为交互式登录shell调用时,或者作为一个非交互式shell使
–login
选项时,如果该文件存在,它将首先从文件/etc/profile
中读取和执行命令。读了这个文件后,它查找~/.bash_profile
、~/.bash_login
和~/.profile
,在该顺序中,并从存在且可读的第一个命令中读取和执行命令。shell可以使用–noprofile
选项禁止该行为。
当一个登录shell退出时,bash将从文件中读取和执行命令~/.bash_logout
和/etc/bash.bash_logout
,如果文件存在。
“profile”
系列的代表文件为~/.bash_profile
,它用于“登录shell”的环境加载,这个“登录shell”既可以是“交互式”的,也可以是“非交互式”的。
通过–noprofile
选项可以阻止系统加载“profile”
系列的startup文件。
登陆过程:
/etc/profile
文件;/etc/bashrc
文件;(macOS中才有这个)~/.bash_profile
文件;~/.bash_login
文件;~/.profile
文件;登出过程:
4. 读取并执行~/.bash_logout
文件;
5. 读取并执行/etc/bash.bash_logout
文件;
为了完成实验,因为我的mac
默认是zsh
,所以我新建了一些系统默认没有提供的startup文件,例如/etc/bash.bash_logout
。然后在每个文件中打印了当前文件名,并将它们之间的显式调用语句注释掉,并打印被调用的文件名,例如下面~/.bash_profile
对~/.bashrc
的显式调用,打印了execute /etc/profile
和execute ~/.bash_profile
,使用su - XX
进行交互式登录,exit
退出登录
[root@localhost ~]# su - chen
Last login: Tue Apr 18 17:15:08 CST 2017 from 192.168.161.1 on pts/2
execute /etc/profile
execute ~/.bash_profile
-bash-4.2$ exit
logout
execute ~/.bash_logout
execute /etc/bash.bash_logout
[root@localhost ~]#
我们看到,因为执行了~/.bash_profile
文件,所以优先级更低的~/.bash_login
和~/.profile
文件并没有被执行。
我们可以删除~/.bash_profile
和~/.bash_login
文件,这样系统就会找到并执行~/.profile
文件:
[root@localhost ~]# mv /home/chen/.bash_profile /home/chen/.bash_profile.bak
[root@localhost ~]# mv /home/chen/.bash_login /home/chen/.bash_login.bak
[root@localhost ~]# su - chen
Last login: Tue Apr 18 17:27:21 CST 2017 on pts/1
execute /etc/profile
execute ~/.profile
-bash-4.2$ exit
logout
execute ~/.bash_logout
execute /etc/bash.bash_logout
[root@localhost ~]#
对于非交互式的登陆shell而言,CentOS规定了startup文件的加载顺序如下:
登陆过程:
/etc/profile
文件;/etc/bashrc
文件;(macOS中才有这个)~/.bash_profile
文件;~/.bash_login
文件;~/.profile
文件;我们注意到,与“交互式登陆shell”相比,“非交互式登陆shell”并没有登出的过程,实验也证实了这一点:
-bash-4.2$ bash --login -c "uname -r"
execute /etc/profile
execute ~/.bash_profile
3.10.0-514.el7.x86_64
-bash-4.2$ # 此时非交互式shell已退出
根据bash手册上的描述:
When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists. This may be inhibited by using the –norc option. The –rcfile file option will force bash to read and execute commands from file instead of ~/.bashrc.
“rc”系列的代表文件为~/.bashrc
,它用于“交互式非登录shell”的环境加载。
通过–norc
选项可以阻止系统加载“rc”
系列的startup文件;通过–rcfile
选项可以使用指定的文件替代系统默认的~/.bashrc
文件。
对于交互式的非登陆shell而言,CentOS规定了startup文件的加载顺序如下:
~/.bashrc
或–rcfile
选项指定的文件这里需要说明,其实“rc”系列startup文件还包括/etc/bashrc
。但是系统并不直接调用这个文件,而是通过~/.bashrc
文件显式地调用它。
为了完成实验,我在每个startup文件中打印了文件名,并将它们之间的显式调用语句注释掉,例如~/.bashrc
对/etc/bashrc
的显式调用。
“交互式非登陆shell”的实验结果如下:
[root@localhost ~]# su chen
execute ~/.bashrc
bash-4.2$ exit
exit
[root@localhost ~]#
细心的用户会发现,startup文件的加载并不像上面所述的那样简单。这是因为在CentOS
中,startup文件之间还存在着默认的显式调用关系,它们是:
~/.bash_profile
显式调用~/.bashrc
文件;~/.bashrc
显式调用/etc/bashrc
文件;再看startup文件
分别打开/etc/profile
和/etc/bashrc
两个文件,我们可以看到:
[root@localhost ~]# head /etc/profile
# /etc/profile
# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
[root@localhost ~]# head /etc/bashrc
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
由此可见,“profile”系列文件的主要目的在于为“登录shell”设置环境变量和启动程序;而“rc”系列文件的主要目的在于设置功能和别名。
顺便提一句,Linux中“rc”
是英文“run command”
的缩写,表示文件中存放需要执行的命令
。其实这也非常符合逻辑,设置功能就要执行shopt命令,而设置别名要执行alias命令。与“rc”系列互补,“profile”
系列用来设置环境变量
,它不会去调用这两个命令,但却经常需要使用export语句
。不信你可以看一看这两个文件。
另外值得一提的是,这两个文件同时提到了一个位置:/etc/profile.d
目录。这个目录用于存放个性化配置脚本,你可以把自己需要的全局配置放入以.sh
结尾的文件中,系统在执行/etc/profile
和/etc/bashrc
文件时,都会择机调用它们。这样做最大的好处是便于维护,而且相对更加安全。
这些文件的编写方法,可以参考目录下已有的文件:
[root@localhost ~]# ls /etc/profile.d/*.sh
/etc/profile.d/256term.sh /etc/profile.d/colorls.sh /etc/profile.d/less.sh
/etc/profile.d/colorgrep.sh /etc/profile.d/lang.sh /etc/profile.d/which2.sh
对于“登录shell”
而言,“交互式”
执行“登陆”
和“登出”
相关的“profile”
系列startup文件,“非交互式”
只执行“登陆”
相关的“profile”
系列startup文件;对于“非登陆shell”
而言,“交互式”
执行“rc”
系列的startup文件,而“非交互式”
执行的配置文件由环境变量BASH_ENV
指定。
Linux中startup文件区分全局和个人:全局startup文件放在/etc
目录下,用于设置所有用户共同的配置,除非你清楚地知道你在做的事情,否则不要轻易改动它们;个人startup文件放在~
目录下,用于设置某个用户的个性化配置。
~/.bash_profile
会显式调用~/.bashrc
文件,而~/.bashrc
又会显式调用/etc/bashrc
文件,这是为了让所有交互式界面看起来一样。无论你是从远程登录(登陆shell),还是从图形界面打开终端(非登陆shell),你都拥有相同的提示符,因为环境变量PS1在/etc/bashrc
文件中被统一设置过。
下面我来对startup文件进行一个完整的总结:
startup文件 | 交互登录 | 非交互登录 | 交互非登录 | 非交互非登录 |
---|---|---|---|---|
/etc/profile(bash ) 或 /etc/zprofile(zsh ) |
直接执行1 | 直接执行1 | ||
~/.bash_profile(bash ) 或 ~/.zprofile(zsh ) |
直接执行2 | 直接执行2 | ||
~/.bash_login | 条件执行2 | 条件执行2 | ||
~/.profile | 条件执行2 | 条件执行2 | ||
~/.bash_logout | 直接执行3 | 不执行 | ||
/etc/bash.bash_logout | 直接执行4 | 不执行 | ||
~/.bashrc(bash ) 或 ~/.zshrc(zsh |
引用执行2.1 | 引用执行2.1 | 直接执行1 | |
/etc/bashrc(bash ) 或 /etc/zshrc(zsh ) |
引用执行2.2 | 引用执行2.2 | 引用执行1.1 |
备注:
没有优先级更高的文件可用
);被其他文件显式调用
的;“非交互非登陆”
shell的配置文件可以由BASH_ENV
环境变量指定;最后我想说的是,知道startup文件何时被执行并不是关键,关键是要理解自己的情况应该去修改哪个startup文件。
如果你想对bash
的功能进行设置或者是定义一些别名,推荐你修改~/.bashrc
文件,这样无论你以何种方式打开shell,你的配置都会生效。而如果你要更改一些环境变量,推荐你修改~/.bash_profile
文件,因为考虑到shell的继承特性,这些更改确实只应该被执行一次(而不是多次)。针对所有用户进行全局设置,推荐你在/etc/profile.d
目录下添加以.sh
结尾的文件,而不是去修改全局startup文件。
参考文章1—/etc/bashrc和/etc/profile区别
参考文章2—关于“.bash_profile”和“.bashrc”区别的总结
参考文章3—Linux的环境配置文件(startup文件)
参考文章4—环境变量:/etc/profile、/etc/bashrc 、~/.profile、~/.bashrc