首頁 > shell教程 閱讀:0更新時間:2020-03-28 02:16:30

Shell變量的作用域:全局變量、環境變量和局部變量

shell 變量的作用域(Scope),就是 Shell 變量的有效范圍(可以使用的范圍)。

在不同的作用域中,同名的變量不會相互干涉,就好像 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 所示。

打開兩個Shell窗口
圖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 所示。
進入Shell子進程
圖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 進程仍然是無效的。請看下圖:環境變量在不同的Shell窗口中無效第一個窗口中的環境變量 a 在第二個窗口中就無效。

環境變量也是臨時的

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

有讀者可能會問,如果我想讓一個變量在所有 Shell 進程中都有效,不管它們之間是否存在父子關系,該怎么辦呢?

只有將變量寫入 Shell 配置文件中才能達到這個目的!Shell 進程每次啟動時都會執行配置文件中的代碼做一些初始化工作,如果將變量放在配置文件中,那么每次啟動進程都會定義這個變量。不知道如何修改配置文件的讀者請猛擊《Shell配置文件的加載》《編寫自己的Shell配置文件》。

beylze編程學院,一個分享編程知識和seo優化知識的網站。跟著beylze一起學習,每天都有進步。

通俗易懂,深入淺出,一篇文章只講一個知識點。

文章不深奧,不需要鉆研,在公交、在地鐵、在廁所都可以閱讀,隨時隨地漲姿勢。

文章不涉及代碼,不燒腦細胞,人人都可以學習。

當你決定關注beylze(公眾號:beylze),你已然超越了90%的其他從業者!

相關文章

優秀教程

国产亚洲欧美日韩