Linux shell是用戶與Linux系統進行交互的媒介,而bash做爲目前Linux系統中最經常使用的shell,它支持的startup文件也並不單一,甚至容易讓人感到費解。本文以CentOS7系統爲例,對bash的startup文件進行一些必要的梳理和總結。shell
根據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
文件的做用是相同的。bash
備註:Debian系統會使用~/.profile
文件取代~/.bash_profile
文件,所以在相關細節上,會與CentOS略有不一樣。less
經過名字的不一樣,咱們能夠直觀地將startup文件分爲「profile」與「rc」兩個系列,其實他們的功能都很相似,可是使用的場景不一樣,這也是你們最容易忽略的地方。ide
所謂的不一樣場景,其實就是shell的運行模式。咱們知道運行中的bash有「交互」和「登錄」兩種屬性,而執行「profile」系列仍是「rc」系列,就與shell的這兩個屬性有關。this
關於bash的運行模式,請參見個人另外一篇博客:
《關於「交互式-非交互式」與「登陸-非登錄」shell的總結》idea
原理上講,「登錄shell」啓動時會加載「profile」系列的startup文件,而「交互式非登錄shell」啓動時會加載「rc」系列的startup文件。spa
根據bash手冊上的描述:.net
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.code
「profile」系列的表明文件爲~/.bash_profile
,它用於「登陸shell」的環境加載,這個「登陸shell」既能夠是「交互式」的,也能夠是「非交互式」的。
經過--noprofile
選項能夠阻止系統加載「profile」系列的startup文件。
對於交互式的登錄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而言,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已退出
根據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文件的加載順序以下:
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文件的加載並不像上面所述的那樣簡單。這是由於在CentOS中,startup文件之間還存在着默認的顯式調用關係,它們是:
1. ~/.bash_profile
顯式調用~/.bashrc
文件;
2. ~/.bashrc
顯式調用/etc/bashrc
文件;
分別打開/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文件。