1. 程式人生 > >linux shell “永久環境變數”、“臨時環境變數”和"普通變數"之完全解讀

linux shell “永久環境變數”、“臨時環境變數”和"普通變數"之完全解讀

        這個年代, 大家寫點書, 也無非就是為了搞點錢, 基本都是羅列一些知識點, 基本都是寫給已經會了的人看的。 真正用心寫書的人, 不多。 如果真正用心寫書, 且站在讀者的角度去寫, 那就少之又少了。

        關於linux shell環境變數, 我看了四本linux相關書的介紹, 結果, 沒有一本書的講解讓我完全滿意, 總感覺沒有說清楚。所以呢, 我打算自己來寫一下,如有不當指出, 請大家指正。

        一. 永久環境變數(實際上屬於檔案, 而不屬於shell, 每開啟一個shell, 都會載入/匯入到shell中, 形成當前shell的臨時環境變數)

        先說說"永久環境變數", 其實, 我也知道, 沒有什麼東西是真正永久的, 這裡的永久是指: 變數儲存在檔案中, 不會因為掉電或者關機而消失。下面, 我們開啟一個linux shell, 並列印HOME的值, 如下:

[[email protected] Desktop]$ echo $HOME
/home/taoge 

       我們看到HOME這個變數的值是/home/taoge, 這個變數的值是從哪裡來的呢? 我們可以看看使用者主目錄下的.bashrc檔案

[[email protected] Desktop]$ cat ~/.bashrc 

      其中的內容為:

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific aliases and functions

       啊? 居然沒有HOME? 不要著急, 先姑且認為是在/etc/bashrc中進行了HOME的設定吧, 在此, 我們不深究, 只需要有這個認識: HOME與檔案~/.bashrc密切相關, 即使斷電或者掉電, 也不怕消失。

      實際上, 當我們開啟一個shell程序的時候, HOME這個永久環境變數會自動匯入到當前的shell中來(為當前shell設定了一個臨時的環境變數), 那這個HOME可不可以被unset掉呢? 我們來看一下:

[[email protected] Desktop]$ echo $HOME
/home/taoge
[[email protected]
Desktop]$ unset HOME [[email protected] Desktop]$ echo $HOME [[email protected] Desktop]$

      我們看到, 當前shell程序中的HOME確實是被unset掉了, 不要著急, 我們另外開啟一個shell程序, 然後看看有沒有HOME,  如下:

[[email protected] Desktop]$ echo $HOME
/home/taoge
[[email protected] Desktop]$
      可以看到, 第二個shell程序中是有HOME的, 這個不難理解, 因為開啟第二個shell程序的時候, 會把~/.bashrc中的永久HOME載入一次, 所以可以看到/home/taoge.

      我們暫時來總結一下: 永久環境變數存在於~/.bashrc檔案中(掉電或者重啟後, 不會消失), 在每個shell啟動的時候, 都會將永久環境變數匯入到shell中, 併成為shell的臨時環境變數, 這個臨時的環境變數可以被unset掉後, 但不會影響其他shell, 因為我們即將會說到, 不同shell的臨時環境變數是彼此獨立的。

      你可能還在糾結並不耐煩地發出疑問:在~/.bashrc中沒有看到HOME啊, 你不是在扯淡麼? 好, 我們自己來把一個變數寫入到~/.bashrc檔案中, 使之成為永久環境變數, ~/.bashrc檔案內容如下:

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific aliases and functions


# define permanent variable by taoge
winner="people who persists"
      我定義winner這個變數的值為“people who persists”, 好, 儲存檔案, 我們來檢視一下winner這個變數, 如下:
[[email protected] Desktop]$ echo $winner

[[email protected] Desktop]$  

      遺憾的是, 我們沒有看到winner, 為什麼呢? 因為現在只是把winner變成了永久環境變數, 這個永久環境變數並沒有載入到當前的shell中來啊! 好吧, 我們關掉當前的shell, 並開啟一個新的shell,  再檢視一次, 如下:

[[email protected] Desktop]$ echo $winner
people who persists
[[email protected] Desktop]$ 

      可以看到, 這次winner有值了, 激動吧。 這樣, 無論以後是重啟linux, 還是怎麼滴, winner就成為了檔案的一部分, 就成了永久的環境變量了。 當然, 你要是把~/.bashrc檔案中的winner那一行刪除了, 然後跟我說:你不是說永久的麼? 現在怎麼不永久啦?  好吧, 你這是在故意找茬。

      二. 臨時的環境變數(屬於當前shell及其子程序)

       上面我們已經說了, winner成了永久的環境變數, 當一個shell開啟的時候, 便會載入這個winner變數, 那麼在當前shell環境中, 這個winner就會變成臨時的環境變數。 之所以說是臨時的, 是因為你可以把他unset掉, 之所以說是環境變數, 意思是說(沒被unset掉的時候), 當前shell程序的子程序可以訪問到該winner, 如下:

[[email protected] Desktop]$ echo $$
7203
[[email protected] Desktop]$ echo $winner
people who persists
[[email protected] Desktop]$ bash
[[email protected] Desktop]$ echo $$
7354
[[email protected] Desktop]$ echo $winner
people who persists
[[email protected] Desktop]$ exit
exit
[[email protected] Desktop]$ echo $$
7203
[[email protected] Desktop]$ 

      我們看到, 當前程序pid是7203, 為它再開一個子shell程序, 子程序的pid為7354, 我們可以看到, 在程序中, 也可以訪問到winner.   

      上面的winner是~/.bashrc中永久環境變數載入而來的, 那我們可不可以自定義臨時環境變數呢? 可以的。 這次, 我們執行a.sh指令碼來做當前shell的子程序, 如下:

[[email protected] Desktop]$ export x="defined in shell"
[[email protected] Desktop]$ vim a.sh
[[email protected] Desktop]$ cat a.sh 
#! /bin/bash
echo $x
[[email protected] Desktop]$ chmod +x a.sh 
[[email protected] Desktop]$ ./a.sh 
defined in shell
[[email protected] Desktop]$ 
     可以看到, 在指令碼子程序中, 也可以訪問x這個臨時的環境變數。 好, 我問個問題, 那別的shell能訪問這個x麼?  我們再開啟另外一個shell, 如下:
[[email protected] Desktop]$ echo $x

[[email protected] Desktop]$  

     肯定是沒有啊, 上面的一些例子都揭露了臨時環境變數的本質: 當前shell的臨時環境變數, 能被自己及其子程序(子shell程序, 子指令碼程序或者子C程式程序)訪問, 但不能被其它shell訪問(相互獨立)。 對了, 我們上面已經討論過了, 臨時的環境變數可以被unset掉。在實際大型的軟體開發中, 編譯大工程, 經常需要用到臨時環境變數。

      三. 普通變數(屬於當前shell程序)

      shell中的普通變數很簡單, 僅能被當前shell訪問, 不能被其子程序訪問, 更不能被其它shell訪問。 當然, 它也可以被unset掉, 測試如下:

[[email protected] Desktop]$ z="f(y)"
[[email protected] Desktop]$ echo $z
f(y)
[[email protected] Desktop]$ echo $$
7578
[[email protected] Desktop]$ bash
[[email protected] Desktop]$ echo $$
7653
[[email protected] Desktop]$ echo $z

[[email protected] Desktop]$ exit
exit
[[email protected] Desktop]$ echo $$
7578
[[email protected] Desktop]$ unset z
[[email protected] Desktop]$ echo $z

[[email protected] Desktop]$
     可見, 確實不能被子shell訪問, 當然, 肯定更不能被其它shell訪問了。   普通變數要提升了臨時的環境變數, 那也很簡單, 加一下export就可以了, 如下:
[[email protected] Desktop]$ z="f(y)"
[[email protected] Desktop]$ echo $z
f(y)
[[email protected] Desktop]$ echo $$
7578
[[email protected] Desktop]$ export z
[[email protected] Desktop]$ bash
[[email protected] Desktop]$ echo $$
7723
[[email protected] Desktop]$ echo $z
f(y)
[[email protected] Desktop]$ exit
exit
[[email protected] Desktop]$ echo $$
7578
[[email protected] Desktop]$ 

       囉嗦地總結一下:shell中的普通變數, 僅能被當前shell訪問, 不能被其子程序訪問, 更不能被其它shell訪問。 當然, 它也可以被unset掉。

      OK,  我覺得我應該說清楚了, 早休息!

       補充: 

      1. 實際上, 我們也可以在~/.bashrc中設定alias別名, 這個用起來很方便, 每個shell(包括子shell)都可以用到。 修改好後, 不用再關掉shell開啟shell了, 直接在當前shell中執行source ~/.bashrc即可。

      2. 如果自己在當前shell中定義一個alias, 那麼僅在當前shell程序中有效, 我們沒法用export使得它在子shell中生效, 畢竟, alias和上面講的變數還是有所區別的。 如果是在指令碼中定義alias, 則也必須用source來執行, 使得alias在當前shell中生效, 我經常這麼玩。