##shell十三問之5:問var=value 在export前後的差在哪?

這次讓我們暫時丟開command line, 先了解一下bash變量(variable)吧...

所謂的變量,就是利用一個固定的"名稱"(name), 來存取一段可以變化的"值"(value)。

###1. 變量設定(set) 在bash中, 你可以用"="來設定或者重新定義變量的內容:

name=value

在設定變量的時候,得遵守如下規則:

  • 等號左右兩邊不能使用分隔符號(IFS),也應避免使用shell的保留元字符(meta charactor);
  • 變量的名稱(name)不能使用$符號;
  • 變量的名稱(name)的首字符不能是數字(number)。
  • 變量的名稱(name)的長度不可超過256個字符。
  • 變量的名稱(name)及變量的值的大小寫是有區別的、敏感的(case sensitive,)

如下是一些變量設定時常見的錯誤:

A= B #=號前後不能有IFS
1A=B #變量名稱不能以數字開頭
$A=B #變量的名稱裡有$
a=B  #這跟a=b是不同的,(這不是錯誤,提醒windows用戶)

如下則是可以接受的設定:

A=" B" #IFS被關閉,參考前面的quoting章節
A1=B   #並非以數字開頭
A=$B   #$可用在變量的值內
This_Is_A_Long_Name=b #可用_連接較長的名稱或值,且有大小區別;

###2. 變量替換(substitution) shell 之所以強大,其中的一個因素是它可以在命令行中對變量作 替換(substitution)處理。 在命令行中使用者可以使用$符號加上變量名稱(除了用=定義變量名稱之外), 將變量值給替換出來,然後再重新組建命令行。

比方:

$ A=ls
$ B=la
$ C=/tmp
$ $A -$B $C

以上命令行的第一個$shell prompt, 並不在命令行之內。 必須強調的是,我們所提的變量替換,只發生在command line上面。 (是的,請讓我們再次回到命令行吧!) 仔細分析,最後那行 command line,不難發現在被執行前(在輸入CR字符之前), $符號對每一個變量作替換處理(將變量的值替換出來再重組命令行), 最後會得出如下命令行:

ls -la /tmp

還記得第二章,我請大家"務必理解"的那兩句嗎? 若你忘了,我這裡重貼一遍:

Note:

若從技術的細節來看,shell會依據IFS(Internal Field Seperator) 將command line所輸入的文字拆解為"字段"(word/field)。 然後再針對特殊字符(meta)先作處理,最後重組整行command line

這裡的$就是command line中最經典的meta之一了, 就是作變量替換的。在日常的shell操作中, 我們常會使用echo命令來查看特定的變量的值, 例如:

$ echo $A -$B $C

我們已學過,echo命令只單純將其argument送至"標準輸出"(stdout, 通常是我們的屏幕)。 所以上面的命令會在屏幕上得到如下結果:

ls -al /tmp

這是由於echo命令在執行時,會先將$A (ls)、$B (la)跟$C (/tmp)給替換出來; 利用shell對變量的替換處理能力,我們在設定變量時就更為靈活了:

A=B
B=$A

這樣,B的變量值就可繼承A變量"當時"的變量值了。 不過,不要以"數學邏輯"來套用變量的設定,比方說:

A=B
B=C

這樣,並不會讓A的變量值變成C。再如:

A=B
B=$A
A=C

同樣也不會讓B的值變成C。

上面是單純定義了兩個不同名稱的變量: A 與 B, 它們的取值分別是C與B。

若變量被重複定義的話,則原有值為新值所取代。(這不正是"可變的量"嗎?_) 當我們在設定變量的時候,請記住這點:用一個名稱存儲一個數值, 僅此而已。

此外, 我們也可以利用命令行的變量替換能力來"擴充"(append)變量的值:

A=B:C:D
A=$A:E

這樣, 第一行我們設定A的值為"B:C:D", 然後,第二行再將值擴充為"B:C:D:E"。

上面的擴充的範例,我們使用分隔符號(:)來達到擴充的目的, 要是沒有分隔符的話,如下是有問題的:

A=BCD
B=$AE

因為第二次是將A的值繼承$AE的替換結果,而非$A再加E。 要解決此問題,我們可用更嚴謹的替換處理:

A=BCD
A=${A}E

上例中,我們使用{}將變量名稱範圍給明確定義出來, 如此一來, 我們就可以將A的變量值從BCD給擴充為BCDE。

Tips: 關於${name}事實上還可以做到更多的變量處理能力, 這些均屬於比較進階階段的變量處理,現階段暫不介紹了, 請大家自行參考資料。

###3. export 變量

嚴格來說,我們在當前shell中所定義的變量,均屬於 "本地變量"(local variable), 只有經過export命令的 "輸出"處理,才能成為"環境變量"(environment variable):

$ A=B
$ export A

或者

$ export A=B

經過export輸出處理之後,變量A就能成為一個環境變量 供其後的命令使用。在使用export的時候,請別忘記 shell在命令行對變量的"替換"(substitution)處理。 比方說:

$ A=B
$ B=C
$ export $A

上面的命令並未將A輸出為"環境變量",而是將B導出 這是因為在這個命令行中,$A會首先被替換為B,然後在"塞回" 作export的參數。

要理解這個export,事實上需要從process(進程)的角度來理解才能透徹。 我們將於下一章為大家說明process(進程)的概念,敬請留意。

####4. 取消變量(unset) 要取消一個變量,在bash中可使用unset命令來處理:

    unset A

export一樣,unset命令行,也同樣會作 變量替換(這其實是shell的功能之一), 因此:

$ A=B
$ B=C
$ unset $A

事實上,所取消的是變量B而不是A。

此外,變量一旦經過unset取消之後, 其結果是將整個變量拿掉,而不是取消變量的值。

如下兩行其實是很不一樣的:

$ A=
$ unset A

第一行只是將變量A設定為"空值"(null value), 但第二行則是讓變量A不存在。 雖然用眼睛來看, 這兩種變量的狀態在如下的命令結果中都是一樣的:

$ A=
$ echo $A

$ unset A
$ echo $A

請學員務必能識別null value 與 unset的本質區別, 這在一些進階的變量處理上是很嚴格的。

比方說:

$ str=    #設為null
$ var=${str=expr} #定義var
$ echo $var

$ echo $str

$ unset str #取消str
$ var=${str=expr} #定義var
$ echo $var
expr
$ echo $str
expr

聰明的讀者(yes, you!),稍加思考的話, 應該不難發現為何同樣的var=${str=expr} 在str為null與unset之下的不同吧? 若你看不出來,那可能是如下原因之一:

  • 你太笨了
  • 不瞭解 var=${str=expr} 這個進階處理
  • 對本篇說明還沒有來得及消化吸收
  • 我講得不好

不知,您選哪個呢?...... _.


书籍推荐