啟動腳本是bash
啟動時自動執行的腳本。用戶可以把一些環境變數的設置和alias
、umask
設置放在啟動腳本中,這樣每次啟動Shell時這些設置都自動生效。思考一下,bash
在執行啟動腳本時是以fork
子Shell方式執行的還是以source
方式執行的?
啟動bash的方法不同,執行啟動腳本的步驟也不相同,具體可分為以下幾種情況。
交互Shell是指用戶在提示符下輸命令的Shell而非執行腳本的Shell,登錄Shell就是在輸入用戶名和密碼登錄後得到的Shell,比如從字元終端登錄或者用telnet
/ssh
從遠程登錄,但是從圖形界面的窗口管理器登錄之後會顯示桌面而不會產生登錄Shell(也不會執行啟動腳本),在圖形界面下打開終端窗口得到的Shell也不是登錄Shell。
這樣啟動bash
會自動執行以下腳本:
首先執行/etc/profile
,系統中每個用戶登錄時都要執行這個腳本,如果係統管理員希望某個設置對所有用戶都生效,可以寫在這個腳本裡
然後依次查找當前用戶主目錄的~/.bash_profile
、~/.bash_login
和~/.profile
三個檔案,找到第一個存在並且可讀的檔案來執行,如果希望某個設置只對當前用戶生效,可以寫在這個腳本裡,由於這個腳本在/etc/profile
之後執行,/etc/profile
設置的一些環境變數的值在這個腳本中可以修改,也就是說,當前用戶的設置可以覆蓋(Override)系統中全局的設置。~/.profile
這個啟動腳本是sh
規定的,bash
規定首先查找以~/.bash_
開頭的啟動腳本,如果沒有則執行~/.profile
,是為了和sh
保持一致。
順便一提,在退出登錄時會執行~/.bash_logout
腳本(如果它存在的話)。
比如在圖形界面下開一個終端窗口,或者在登錄Shell提示符下再輸入bash
命令,就得到一個交互非登錄的Shell,這種Shell在啟動時自動執行~/.bashrc
腳本。
為了使登錄Shell也能自動執行~/.bashrc
,通常在~/.bash_profile
中調用~/.bashrc
:
if [ -f ~/.bashrc ]; then . ~/.bashrc fi
這幾行的意思是如果~/.bashrc
檔案存在則source
它。多數Linux發行版在創建帳戶時會自動創建~/.bash_profile
和~/.bashrc
腳本,~/.bash_profile
中通常都有上面這幾行。所以,如果要在啟動腳本中做某些設置,使它在圖形終端窗口和字元終端的Shell中都起作用,最好就是在~/.bashrc
中設置。
下面做一個實驗,在~/.bashrc
檔案末尾添加一行(如果這個檔案不存在就創建它):
export PATH=$PATH:/home/akaedu
然後關掉終端窗口重新打開,或者從字元終端logout
之後重新登錄,現在主目錄下的程序應該可以直接輸程序名運行而不必輸入路徑了,例如:
~$ a.out
就可以了,而不必
~$ ./a.out
為什麼登錄Shell和非登錄Shell的啟動腳本要區分開呢?最初的設計是這樣考慮的,如果從字元終端或者遠程登錄,那麼登錄Shell是該用戶的所有其它進程的父進程,也是其它子Shell的父進程,所以環境變數在登錄Shell的啟動腳本裡設置一次就可以自動帶到其它非登錄Shell裡,而Shell的本地變數、函數、alias
等設置沒有辦法帶到子Shell裡,需要每次啟動非登錄Shell時設置一遍,所以就需要有非登錄Shell的啟動腳本,所以一般來說在~/.bash_profile
裡設置環境變數,在~/.bashrc
裡設置本地變數、函數、alias
等。如果你的Linux帶有圖形系統則不能這樣設置,由於從圖形界面的窗口管理器登錄並不會產生登錄Shell,所以環境變數也應該在~/.bashrc
裡設置。
為執行腳本而fork
出來的子Shell是非交互Shell,啟動時執行的腳本檔案由環境變數BASH_ENV
定義,相當於自動執行以下命令:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
如果環境變數BASH_ENV
的值不是空字元串,則把它的值當作啟動腳本的檔案名,source
這個腳本。