跳轉到

2000:Bash 2.0——重寫與陣列#

事件#

1996 年 12 月 bash 2.0 問世(1990 年代末開發,2000 年前後的 2.x 版本廣泛普及),由 Chet Ramey 主導了 bash 的第一次解析器大重寫,並加入陣列與國際化。這是 bash 語言能力的一次躍升。

新語法與特性及其理論、實用原因#

1. 陣列(arr=(a b c)、${arr[@]}、${arr[0]})#

  • 理論原因:序列資料是最低要求的抽象,ksh(1983)早已證明。
  • 實用原因:for x in "${files[@]}"; do ... 可以正確處理含空格的檔名——這是 POSIX 語法做不到的。
  • 彌補缺陷:Bourne/POSIX shell 只能用位置參數或換行分隔字串模擬陣列,含空格的檔名是災難。

2. $(( )) 算術展開標準化#

  • 理論原因:繼承 ksh 語法並成為 bash 標準。
  • 實用原因:內建整數運算,不需 fork expr。
  • 彌補缺陷:Bourne shell 無內建算術。

3. ${var#pattern}、${var%pattern}、${var/pat/repl} 字串操作#

  • 理論原因:字串是 shell 唯一的型別,字串操作應內建而非外部程式。
  • 實用原因:file="${path##*/}" 取檔名、${path%.*} 去副檔名,不需 fork sed/awk。
  • 彌補缺陷:以前字串處理必須 fork sed、cut、basename,效能差且引號陷阱多。

4. 國際化(i18n)與 locale 支援#

  • 實用原因:非英語使用者(訊息翻譯、字元編碼)的需求。

5. 新解析器架構#

  • 理論原因:1990 年代的解析器有語意歧義(如 $() 嵌套、引號處理),重寫以修正語言定義。
  • 實用原因:為之後 25 年的功能擴充(bash 3.x、4.x)打好地基。

程式範例:Bash 2.0 的新語法#

# 1. 陣列:正確處理含空格的檔名(POSIX 語法做不到)
files=("my a.txt" "b c.txt" "d.txt")
for f in "${files[@]}"; do     # 引號 + [@] 防止空格分裂
  echo "處理: $f"
done
echo "共 ${#files[@]} 個檔案"
# 2. 算術展開標準化
x=10
x=$(( x + 1 ))        # 內建,不需 fork expr
echo $(( x % 3 ))
# 3. 內建字串操作:不需 fork sed/cut/basename
path=/usr/local/bin/prog.c
echo "${path##*/}"      # prog.c    取檔名(取代 basename)
echo "${path%.*}"       # /usr/local/bin/prog(去副檔名)
echo "${path#*/usr/}"   # local/bin/prog.c(從頭去樣式)
echo "${path/bin/BIN}"  # 取代第一個出現
# 對比:以前的寫法(每次 fork 外部程式)
# echo "$path" | sed 's/.*\///'     # 慢 + 引號陷阱
# basename "$path"
# 4. 國際化
LC_ALL=zh_TW.UTF-8 bash --version   # locale 支援

歷史意義#

Bash 2.x 讓 bash 的語法表達力超越 POSIX 標準,「POSIX sh」與「bash」正式成為兩種可區分的腳本方言。之後 2007 年 bash 3.2、2009 年 bash 4.0 持續擴充。

彌補了什麼缺陷#

彌補了 POSIX shell「無陣列、無內建字串操作」的表達力缺陷——bash 選擇「相容 POSIX 但超越 POSIX」的路線。

相關條目#