Bash 環境變數的那些事

2018-12-23 15:12:00

初學者可以在此教學中瞭解環境變數。

bash 變數,尤其是討厭的環境變數,已經是一個老生常談的話題了。我們也更應該對它有一個詳細的了解,讓它為我們所用。

下面就開啟終端,開始吧。

環境變數

HOME (LCTT 譯註:雙關語)除了是你脫下帽子愜意休息的地方,同時也是 Linux 中的一個變數,它是當前使用者主目錄的路徑:

echo $HOME

以上這個命令會顯示當前使用者的主目錄路徑,通常都在 /home/<your username> 下。

顧名思義,變數的值是可以根據上下文變化的。實際上,Linux 系統中每一個使用者的 HOME 變數都是不一樣的,當然你也可以這樣自行更改 HOME 變數的值:

HOME=/home/<your username>/Documents

以上這個命令將會把 HOME 變數設定為你的 Documents 目錄。

其中有三點需要留意:

  1. = 符號和其兩側的內容之間不加空格。空格在 shell 中有專門的意義,不能隨意地在任何地方新增空格。
  2. 如果你需要對變數進行賦值,只需要使用變數名稱就可以了。但如果需要讀取或者使用變數的值,需要在變數前面加上一個 $ 號。
  3. 更改 HOME 變數具有一定的風險。有很多程式是依賴於 HOME 變數的,更改 HOME 變數可能會導致一些不可預見的結果。例如,如果按照上面的方式更改了 HOME 變數,然後執行不帶有任何引數的 cd 命令,在通常情況下,會跳轉到使用者的主目錄下,但在這個時候,會跳轉到 HOME 變數指定的目錄下。

上面第 3 點中環境變數的更改並不是持久有效的,在終端關閉後重新開啟終端,又或者是新建一個終端,執行 echo $HOME 命令輸出的仍然會是初始的值,而不是重新自定義的值。

在討論如何持久地更改一個環境變數之前,我們先來看一下另一個比較重要的環境變數。

PATH 變數

PATH 變數中存放了一系列目錄,而且是放置了可執行程式的目錄。正是由於 PATH 變數的存在,讓你不需要知道應用程式具體安裝到了什麼目錄,而 shell 卻可以正確地找到這些應用程式。

如果你檢視 PATH 變數的值,大概會是以下這樣:

$ echo $PATH/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin

每兩個目錄之間使用冒號 : 分隔。如果某個應用程式的所在目錄不在 PATH 變數中,那麼執行的時候就需要宣告應用程式的目錄讓 shell 能夠找到。

/home/<user name>/bin/my_program.sh

例如以上命令就會執行當前使用者 bin/ 目錄下的 my_program.sh 檔案。

有一個常見的問題:如果你不希望弄亂系統的 bin/ 目錄,同時也不希望你自己的檔案被其它人執行,還不想每次執行的時候都要輸入完整的路徑,那麼,你可以在你的主目錄中建立一個獨立的 bin/ 目錄:

mkdir $HOME/bin

然後將這個目錄新增到 PATH 變數中:

PATH=$PATH:$HOME/bin

然後 /home/<user name>/bin/ 目錄就會出現在 PATH 變數中了。但正如之前所說,這個變更只會在當前的 shell 生效,當前的 shell 一旦關閉,環境變數的值就又恢復原狀了。

如果要讓變更對當前使用者持續生效,就不能在 shell 中直接執行對應的變更,而是應該將這些變更操作寫在每次啟動 shell 時都會執行的檔案當中。這個檔案就是當前使用者主目錄中的 .bashrc 檔案。檔名前面的點號表明這是一個隱藏檔案,執行普通的 ls 命令是不會將這個檔案顯示出來的,但只要在 ls 命令中加入 -a 引數就可以看到這個檔案了。

你可以使用諸如 kategeditnano 或者 vim 這些文字編輯器來開啟 .bashrc 檔案(但不要用 LibreOffice Writer,它是一個文書處理軟體,跟前面幾個文字編輯器完全不同)。開啟 .bashrc 檔案之後,你會看見裡面放置了一些 shell 命令,是用於為當前使用者設定環境的。

在檔案的末尾新增新行並輸入以下內容:

export PATH=$PATH:$HOME/bin

儲存並關閉 .bashrc 檔案,接下來你就會看到 export 語句的效果。執行以下的命令讓剛才的修改立即生效:

source .bashrc

剛才執行的 source 命令讓 .bashrc 檔案在當前的 shell 立即生效,並且對於之後開啟的 shell 都會有效。因此另一個等效的方法是退出並重新進入 shell,但這樣也太麻煩了。

現在,你的 shell 就能自動尋找到 /home/<user name>/bin/ 下的程式了,執行這個目錄下的程式也不需要完整地寫出程式的路徑。

自定義變數

當然,你也可以定義自己的變數。剛才我們看到的變數名稱都是全大寫的,實際上變數名稱的定義還是比較靈活的

定義新變數的過程非常直觀,直接對它賦值就可以了:

new_variable="Hello"

然後可以用以下的方式讀取到已定義變數的值:

echo $new_variable

程式的正常工作離不開各種變數,例如要將某個選項設定為開啟,又或者讓程式找到所需的程式碼庫,都需要使用變數。在 bash 中執行程式的時候會生成一個子 shell,這個子 shell 和執行原程式的父 shell 並不是完全一樣的,只是繼承了父 shell 的部分內容,而且預設是不繼承父 shell 中的變數的。因為變數預設情況下是區域性變數,出於安全原因,一個 shell 中的區域性變數不會被另一個 shell 讀取到,即使是子 shell 也不可以。

下面舉一個例子。首先定義一個變數:

robots="R2D2 & C3PO"

然後執行:

bash

現在是在 bash shell 中建立了一個子 shell。

執行這個命令看看還能不能讀取到剛才定義的變數:

echo $robots

你會發現讀取不到。

還是在這個子 shell 中,為 robots 變數賦一個不同的值:

robots="These aren't the ones you are looking for"

再讀取一次:

$ echo $robotsThese aren't the ones you are looking for

退出這個子 shell:

exit

然後再看一下現在 robots 變數的值:

$ echo $robotsR2D2 & C3P0

這一個特性可以有效避免設定過程中產生混亂,同時也會導致一個問題:如果程式中需要設定變數,但卻由於子 shell 的原因無法正常存取到這個變數,該如何解決呢?這個時候就需要用到 export 了。

重複一次剛才的過程,但這一次不是通過 robots="R2D2 & C3PO" 方式來設定變數,而是使用 export 命令:

export robots="R2D2 & C3PO"

現在你會發現,在進入子 shell 之後,robots 變數的值仍然是最初賦予的值。

要注意的是,儘管子 shell 會繼承通過 export 匯出的變數,但如果在子 shell 中對這個變數重新賦值,是不會影響到父 shell 中對應變數的。

如果要檢視所有通過 export 匯出的變數,可以執行以下命令:

export -p

自定義的變數會顯示在這個列表的末尾。這個列表中還有一些常見的變數:例如 USER 的值是當前使用者的使用者名稱,PWD 的值是當前使用者當前所在的目錄,而 OLDPWD 的值則是當前使用者上一個存取過的目錄。因此如果執行:

cd -

就會切換到上一個存取過的目錄,那是因為 cd 命令讀取到了 OLDPWD 變數的值。

你也可以使用 env 命令檢視所有環境變數。

如果要取消匯出一個變數,可以加上 -n 引數:

export -n robots

接下來

了解過環境變數的知識之後,你已經到達了可能對自己和他人造成危險的水平,接下來就需要了解如何通過使用別名來讓環境變得更安全、更友好以保護自己了。