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%.*}去副檔名,不需 forksed/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」的路線。