Shell腳本 全局變量、局部變量


在不同的作用域中,同名的變量不會相互干涉,就好像 A 班有個叫小明的同學,B 班也有個叫小明的同學,雖然他們都叫小明(對應於變量名),但是由於所在的班級(對應於作用域)不同,所以不會造成混亂。但是如果同一個班級中有兩個叫小明的同學,就必須用類似於“大小明”、“小小明”這樣的命名來區分他們。

Shell 變量的作用域可以分為三種:

  • 有的變量只能在函數內部使用,這叫做局部變量(local variable);
  • 有的變量可以在當前 Shell 進程中使用,這叫做全局變量(global variable);
  • 而有的變量還可以在子進程中使用,這叫做環境變量(environment variable)。

Shell 局部變量

Shell 也支持自定義函數,但是 Shell 函數和 C++JavaC# 等其他編程語言函數的一個不同點就是:在 Shell 函數中定義的變量默認也是全局變量,它和在函數外部定義變量擁有一樣的效果。請看下面的代碼:

  1. #!/bin/bash
  2. #定義函數
  3. function func(){
  4. a=99
  5. }
  6. #調用函數
  7. func
  8. #輸出函數內部的變量
  9. echo $a

輸出結果:
99

a 是在函數內部定義的,但是在函數外部也可以得到它的值,證明它的作用域是全局的,而不是僅限於函數內部。

要想變量的作用域僅限於函數內部,可以在定義時加上local命令,此時該變量就成了局部變量。請看下面的代碼:

  1. #!/bin/bash
  2. #定義函數
  3. function func(){
  4. local a=99
  5. }
  6. #調用函數
  7. func
  8. #輸出函數內部的變量
  9. 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 的代碼如下:

  1. #!/bin/bash
  2. echo $a
  3. b=200

b.sh 的代碼如下:

  1. #!/bin/bash
  2. 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 進程以及所有的子進程有效,如果最頂層的父進程被關閉了,那么環境變量也就隨之消失了,其它的進程也就無法使用了,所以說環境變量也是臨時的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM