在不同的作用域中,同名的變量不會相互干涉,就好像 A 班有個叫小明的同學,B 班也有個叫小明的同學,雖然他們都叫小明(對應於變量名),但是由於所在的班級(對應於作用域)不同,所以不會造成混亂。但是如果同一個班級中有兩個叫小明的同學,就必須用類似於“大小明”、“小小明”這樣的命名來區分他們。
Shell 變量的作用域可以分為三種:
- 有的變量只能在函數內部使用,這叫做局部變量(local variable);
- 有的變量可以在當前 Shell 進程中使用,這叫做全局變量(global variable);
- 而有的變量還可以在子進程中使用,這叫做環境變量(environment variable)。
Shell 局部變量
Shell 也支持自定義函數,但是 Shell 函數和 C++、Java、C# 等其他編程語言函數的一個不同點就是:在 Shell 函數中定義的變量默認也是全局變量,它和在函數外部定義變量擁有一樣的效果。請看下面的代碼:
- #!/bin/bash
- #定義函數
- function func(){
- a=99
- }
- #調用函數
- func
- #輸出函數內部的變量
- echo $a
輸出結果:
99
a 是在函數內部定義的,但是在函數外部也可以得到它的值,證明它的作用域是全局的,而不是僅限於函數內部。
要想變量的作用域僅限於函數內部,可以在定義時加上local
命令,此時該變量就成了局部變量。請看下面的代碼:
- #!/bin/bash
- #定義函數
- function func(){
- local a=99
- }
- #調用函數
- func
- #輸出函數內部的變量
- echo $a
輸出結果為空,表明變量 a 在函數外部無效,是一個局部變量。
Shell 變量的這個特性和 JavaScript 中的變量是類似的。在 JavaScript 函數內部定義的變量,默認也是全局變量,只有加上var
關鍵字,它才會變成局部變量。
本節只是演示了函數的定義和調用,並沒有對語法細節作過多說明,后續我們將在《Shell函數》一節中進行深入講解。
Shell 全局變量
所謂全局變量,就是指變量在當前的整個 Shell 進程中都有效。每個 Shell 進程都有自己的作用域,彼此之間互不影響。在 Shell 中定義的變量,默認就是全局變量。
想要實際演示全局變量在不同 Shell 進程中的互不相關性,可在圖形界面下同時打開兩個 Shell,或使用兩個終端遠程連接到服務器(SSH)。
首先打開一個 Shell 窗口,定義一個變量 a 並賦值為 99,然后打印,這時在同一個 Shell 窗口中是可正確打印變量 a 的值的。然后再打開一個新的 Shell 窗口,同樣打印變量 a 的值,但結果卻為空,如圖 1 所示。

圖1:打開兩個 Shell 窗口
這說明全局變量 a 僅僅在定義它的第一個 Shell 進程中有效,對新的 Shell 進程沒有影響。這很好理解,就像小王家和小徐家都有一部電視機(變量名相同),但是同一時刻小王家和小徐家的電視中播放的節目可以是不同的(變量值不同)。
需要強調的是,全局變量的作用范圍是當前的 Shell 進程,而不是當前的 Shell 腳本文件,它們是不同的概念。打開一個 Shell 窗口就創建了一個 Shell 進程,打開多個 Shell 窗口就創建了多個 Shell 進程,每個 Shell 進程都是獨立的,擁有不同的進程 ID。在一個 Shell 進程中可以使用 source 命令執行多個 Shell 腳本文件,此時全局變量在這些腳本文件中都有效。
例如,現在有兩個 Shell 腳本文件,分別是 a.sh 和 b.sh。a.sh 的代碼如下:
- #!/bin/bash
- echo $a
- b=200
b.sh 的代碼如下:
- #!/bin/bash
- echo $b
打開一個 Shell 窗口,輸入以下命令:
[c.biancheng.net]$ a=99 [c.biancheng.net]$ . ./a.sh 99 [c.biancheng.net]$ . ./b.sh 200
這三條命令都是在一個進程中執行的,從輸出結果可以發現,在 Shell 窗口中以命令行的形式定義的變量 a,在 a.sh 中有效;在 a.sh 中定義的變量 b,在 b.sh 中也有效,變量 b 的作用范圍已經超越了 a.sh。
注意,必須在當前進程中運行 Shell 腳本,不能在新進程中運行 Shell 腳本,不了解的讀者請轉到《執行Shell腳本》。
Shell 環境變量
全局變量只在當前 Shell 進程中有效,對其它 Shell 進程和子進程都無效。如果使用export
命令將全局變量導出,那么它就在所有的子進程中也有效了,這稱為“環境變量”。
環境變量被創建時所處的 Shell 進程稱為父進程,如果在父進程中再創建一個新的進程來執行 Shell 命令,那么這個新的進程被稱作 Shell 子進程。當 Shell 子進程產生時,它會繼承父進程的環境變量為自己所用,所以說環境變量可從父進程傳給子進程。不難理解,環境變量還可以傳遞給孫進程。
注意,兩個沒有父子關系的 Shell 進程是不能傳遞環境變量的,並且環境變量只能向下傳遞而不能向上傳遞,即“傳子不傳父”。
創建 Shell 子進程最簡單的方式是運行 bash 命令,如圖 2 所示。

圖2:進入 Shell 子進程
通過exit
命令可以一層一層地退出 Shell。
下面演示一下環境變量的使用:
[c.biancheng.net]$ a=22 #定義一個全局變量 [c.biancheng.net]$ echo $a #在當前Shell中輸出a,成功 22 [c.biancheng.net]$ bash #進入Shell子進程 [c.biancheng.net]$ echo $a #在子進程中輸出a,失敗 [c.biancheng.net]$ exit #退出Shell子進程,返回上一級Shell exit [c.biancheng.net]$ export a #將a導出為環境變量 [c.biancheng.net]$ bash #重新進入Shell子進程 [c.biancheng.net]$ echo $a #在子進程中再次輸出a,成功 22 [c.biancheng.net]$ exit #退出Shell子進程 exit [c.biancheng.net]$ exit #退出父進程,結束整個Shell會話
可以發現,默認情況下,a 在 Shell 子進程中是無效的;使用 export 將 a 導出為環境變量后,在子進程中就可以使用了。export a
這種形式是在定義變量 a 以后再將它導出為環境變量,如果想在定義的同時導出為環境變量,可以寫作export a=22
。
我們一直強調的是環境變量在 Shell 子進程中有效,並沒有說它在所有的 Shell 進程中都有效;如果你通過終端創建了一個新的 Shell 窗口,那它就不是當前 Shell 的子進程,環境變量對這個新的 Shell 進程仍然是無效的。請看下圖:

第一個窗口中的環境變量 a 在第二個窗口中就無效。
環境變量也是臨時的
通過 export 導出的環境變量只對當前 Shell 進程以及所有的子進程有效,如果最頂層的父進程被關閉了,那么環境變量也就隨之消失了,其它的進程也就無法使用了,所以說環境變量也是臨時的。