問題
在使用linux
桌面環境(通常是ubuntu/debian/deepin
等版本的linux
)的時候,新增環境變量後,會使用source /etc/profile
命令使新的環境變量立刻生效而不用重新啓動系統。但經常會遇到使用source /etc/profile
命令之後,新的環境變量只能在當前終端裏面有效,而在新打開的終端中,使用新的環境變量就找不到了。
先通過操作來複現一下這個過程,我使用的linux
分支是deepin
(其他版本的類似),通過圖形界面打開終端操作進入,準備添加一個新的變量testEnv
。
# 查看系統中,是否已經存在名字爲 testEnv 的環境變量,如果輸出爲空,表示環境變量不存在
echo $testEnv
# 環境變量不存在,就添加 testEnv 到環境變量
sudo bash -c "echo testEnv=888888 >> /etc/profile"
# 輸出/etc/profile最後一行,查看是否添加成功
tail -1 /etc/profile
# testEnv=888888
# 使 testEnv 環境變量生效
source /etc/profile
# 查看環境變量 testEnv 的值,如果輸出 888888 ,表示環境變量創建成功
echo $testEnv
# 888888
新建一個終端窗口,看下是否可以輸出環境變量testEnv
的值。
# 輸出結果爲空
echo $testEnv
但是,只要重啓系統,一切就正常了。
問題在於爲什麼?
知識點
我們知道,linux
中環境變量是通過配置文件添加的,在系統啓動的時候,通過加載不同的配置文件來初始化環境變量,所以環境變量找不到的問題,歸根結底是配置文件的加載問題。搞清楚linux
中配置文件的加載順序,上面遇到的問題也就不難理解了。
shell
是用戶與Linux
系統進行交互的媒介,它在運行時具有兩種屬性,即“交互”與“登陸”,由此衍生出交互式登錄和非交互式登錄兩種模式。
-
交互式登錄
shell
進程是指直接通過某終端輸入賬號密碼後登錄打開的shell
進程,如使用ssh
或者堡壘機進行遠程主機連接,或者使用su - username
或者su -l username
執行的登錄用戶切換等。 -
非交互式登錄
shell
進程:圖形界面下打開的終端、su username
執行的登錄切換、直接運行腳本或者bash -c
執行一段命令的時候。
linux
中常見的配置文件有/etc/profile
、~/.bash_profile
、~/.bashrc
、/etc/bashrc
和/etc/profile.d/*
。關於配置文件加載順序的說法,網上有很多,看起來也不盡相同,其實主要區別在與不同的linux
發行版,包含的配置文件也是有很大區別的,即使有名字相同的配置文件,配置文件裏面的內容也是大相徑庭。但是基本上所有的linux
發行版都會包括/etc/profile
(登錄後讀取的第一個配置文件)和~/.bashrc
兩個配置文件。
對於交互式登錄shell來說,一定會讀取的配置文件的順序是/etc/profile --> ~/bashrc
。
對於非交互式登錄shell來說,一定會讀取的配置文件屬性是~/.bashrc
,如果~/.bash_profile
存在的話,順序是這樣的~/.bash_profile --> ~/.bashrc
。
對於其他的各種常見配置文件的讀取,以及是讀取,主要取決於/etc/profile
或者 ~/bashrc
裏面的具體內容,比如在centos7
的/etc/profile
中有如下一段代碼,是用來載入/etc/profile.d/*.sh
配置文件的。
for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done
deepin
系統中的.bashrc
裏面有一段代碼,用來讀取命令別名聲明文件。
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
所以,系統配置文件的讀取順序,需要根據系統版本的不同去了解讀取順序。
每次在配置文件中配置的新環境變量,只會對隨後新啓動的shell
進程生效,如果想讓配置文件立即生效,需要讓shell進程重讀配置文件,這就需要進行類似source /etc/profile
或者 . /etc/profile
這樣的操作。
問題分析及解決
一般遇到本文開頭說到的問題的同學,都是在圖形界面下使用終端的配置的環境變量,然後通過source /etc/profile
重新讀取配置文件,然後打開一個新的終端的時候,使用命令就是出現comand not found
的問題。
結合上面的知識點看下,在圖形界面下使用的終端屬於非交互式登錄的shell,以我使用的deepin
系統爲例,新開一個終端時,讀取的配置文件應該是~/.bashrc
。而新增的環境變量配置在/etc/profile
,所以出現在新開終端找不到環境變量的問題。
解決辦法:
- 在新開終端,執行
source /etc/profile
,比較麻煩 - 將環境變量配置在,
~/.bashrc
中,可以解決 - 在
~/.bashrc
中添加source /etc/profile
,這樣就可以爲每一個新開的終端重新讀取一次/etc/profile
配置文集,可以解決,多次讀取/etc/profile
沒有發現有什麼副作用。
補充
網上早期很多關於java
、node
等的環境變量配置的文章,感覺都是針對搭建centos
服務器或者測試機的,他們之所以沒有這個問題,是因爲服務器基本都是通過ssh
遠程登錄,是交互式登錄模式的,每次打開一個新的遠程連接,都會重新讀取/etc/profile
,所以不會有command not found
的問題。而個人用的電腦,基本都是圖形界面直接操作,所以會遇到比較多的這種問題。
<完>