3

Linux-环境-profile和rc的区别.md

 3 years ago
source link: https://wetts.github.io/2020/03/14/%E7%B3%BB%E7%BB%9F&%E6%9C%8D%E5%8A%A1%E5%99%A8/Linux/Linux-%E7%8E%AF%E5%A2%83-profile%E5%92%8Crc%E7%9A%84%E5%8C%BA%E5%88%AB/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

转自:https://blog.csdn.net/sch0120/article/details/70256318

bash 的 startup 文件

Linux shell 是用户与 Linux 系统进行交互的媒介,而 bash 作为目前 Linux 系统中最常用的 shell,它支持的 startup 文件也并不单一,甚至容易让人感到费解。本文以 CentOS7 系统为例,对 bash 的 startup 文件进行一些必要的梳理和总结。

根据bash手册上的描述:

  • /etc/profile: The systemwide initialization file, executed for login shells
  • /etc/bash.bash_logout: The systemwide login shell cleanup file, executed when a login shell exits
  • ~/.bash_profile: The personal initialization file, executed for login shells
  • ~/.bashrc: The individual per-interactive-shell startup file
  • ~/.bash_logout: The individual login shell cleanup file, executed when a login shell exits

此外,bash 还支持 ~/.bash_login~/.profile 文件,作为对其他 shell 的兼容,它们与 ~/.bash_profile 文件的作用是相同的。

备注:Debian系统会使用 ~/.profile 文件取代 ~/.bash_profile文件,因此在相关细节上,会与 CentOS 略有不同。

“profile”与“rc”系列

通过名字的不同,我们可以直观地将 startup 文件分为“profile”与“rc”两个系列,其实他们的功能都很类似,但是使用的场景不同,这也是大家最容易忽略的地方。

所谓的不同场景,其实就是 shell 的运行模式。我们知道运行中的 bash 有“交互”和“登陆”两种属性,而执行“profile”系列还是“rc”系列,就与shell的这两个属性有关。

原理上讲,“登陆 shell”启动时会加载“profile”系列的 startup 文件,而“交互式非登陆 shell”启动时会加载“rc”系列的 startup 文件。

“profile”系列的执行场景

根据 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.

“profile”系列的代表文件为 ~/.bash_profile,它用于“登录 shell”的环境加载,这个“登录 shell”既可以是“交互式”的,也可以是“非交互式”的。

通过 --noprofile 选项可以阻止系统加载“profile”系列的 startup 文件。

交互式登陆 shell

对于交互式的登陆 shell 而言,CentOS 规定了 startup 文件的加载顺序如下:

登陆过程:

  1. 读取并执行 /etc/profile 文件;
  2. 读取并执行 ~/.bash_profile 文件;
    • 若文件不存在,则读取并执行 ~/.bash_login 文件;
    • 若文件不存在,则读取并执行 ~/.profile 文件;

登出过程:

  1. 读取并执行 ~/.bash_logout 文件;
  2. 读取并执行 /etc/bash.bash_logout 文件;

为了完成实验,我新建了一些系统默认没有提供的 startup 文件,例如 /etc/bash.bash_logout。然后在每个文件中打印了文件名,并将它们之间的显式调用语句注释掉,例如 ~/.bash_profile 对 ~/.bashrc 的显式调用。

“交互式登陆shell”的实验结果如下:

[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

对于非交互式的登陆 shell 而言,CentOS 规定了 startup 文件的加载顺序如下:

登陆过程:

  1. 读取并执行 /etc/profile 文件;
  2. 读取并执行 ~/.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已退出

“rc”系列的执行场景

根据 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

对于交互式的非登陆 shell 而言,CentOS 规定了 startup 文件的加载顺序如下:

  1. 读取并执行 ~/.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 文件的默认调用关系

细心的用户会发现,startup 文件的加载并不像上面所述的那样简单。这是因为在 CentOS 中,startup 文件之间还存在着默认的显式调用关系,它们是:

  1. ~/.bash_profile 显式调用 ~/.bashrc 文件;
  2. ~/.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 直接执行1 直接执行1 - - ~/.bash_profile 直接执行2 直接执行2 - - ~/.bash_login 条件执行2 条件执行2 - - ~/.profile 条件执行2 条件执行2 - - ~/.bash_logout 直接执行3 不执行 - - /etc/bash.bash_logout 直接执行4 不执行 - - ~/.bashrc 引用执行2.1 引用执行2.1 直接执行1 - /etc/bashrc 引用执行2.2 引用执行2.2 引用执行1.1 -
  1. “直接执行”表示此文件被系统直接调用,它的执行是无条件的;
  2. “条件执行”表示此文件被系统调用是有先决条件的(没有优先级更高的文件可用);
  3. “引用执行”表示此文件不是被系统直接调用的,而是被其他文件显式调用的;
  4. 后面的数字表示文件被调用的顺序,数字越大调用越靠后;
  5. “非交互非登陆” shell 的配置文件可以由 BASH_ENV 环境变量指定;

最后我想说的是,知道 startup 文件何时被执行并不是关键,关键是要理解自己的情况应该去修改哪个 startup 文件。

如果你想对 bash 的功能进行设置或者是定义一些别名,推荐你修改 ~/.bashrc 文件,这样无论你以何种方式打开 shell,你的配置都会生效。而如果你要更改一些环境变量,推荐你修改 ~/.bash_profile 文件,因为考虑到 shell 的继承特性,这些更改确实只应该被执行一次(而不是多次)。针对所有用户进行全局设置,推荐你在 /etc/profile.d 目录下添加以 .sh 结尾的文件,而不是去修改全局 startup 文件。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK