ksh 是 UNIX/Linux 下流行的 shell 語言,ksh93 是 ksh 的增強型版本;相比於 ksh,ksh93 提供了更接近於高級語言的特性,包括 c 風格的 for 循環,關聯數組,名字引用,複合變數和更方便的字元串操作,本文討論了這些高級特性並說明它們的應用。
ksh 是各種 UNIX 下的主要 shell 編程語言,許許多多的 UNIX 開發人員每天都在使用 ksh 做為它們日常的工作工具,當前比較流行的 ksh 版本主要有兩個,ksh88 和 ksh93 ;相對於 ksh88,ksh93 提供的特性讓 shell 編程人員的效率更加高效,下面我們逐一討論這些特性。
c 風格的 for 循環
傳統的 shell for 循環使用 for i in set 形式:
for i in 1 2 3 4 5 do echo $i done |
ksh93 提供了對 c 風格 for 循環的支持,如下所示:
for((i=0; i<5; i++)) do echo $i done 對於在“ (( ”,“ )) ”中出現的 shell 變數,不需要在這些變數前加 $ 符號,比如 |
這項功能的加入也許是為了適應 c 編程人員眾多這個事實,所以受到 c 程序員的廣泛歡迎。
count=5 for((i=0; i<count; i++)) do echo $i done |
關聯數組
普通數組使用整數做為下標,關聯數組則是使用字元串作為下標。使用關聯數組可以很容易的將兩方相互聯繫起來,這兩方在關聯數組中表示為數組字元串下標和數組值。
要使用關聯數組,首先要聲明它,下行語句聲明 dict 為關聯數組。
typeset -A dict |
有兩種方法可以給 dict 赴初值;這是第一種,
dict[tree]="a lot of leaves" dict[apple]="eclipse fruites" |
這是第二種,
dict=( [tree]="a lot of leaves" [apple]="eclipse fruit" ) |
要遍歷 dict,使用如下代碼
for i in ${!dict[*]}; # ${!dict[*]} 返回關聯數組 dict 的所有下標 do echo ${dict[$i]}; # $i 是 dict 下標; ${dict[$i]} 取出 dict 的每個元素的值 done |
名字引用
名字引用使函數參數傳遞,引用和修改更加簡單。在沒有引入名字引用之前,為了能在函數內部訪問實參,一種可選的方法是使用 eval 來實現間接變數引用,ksh93 使用名字引用使得這類代碼實現更加直觀和易讀。下例在函數 foo 中用“ typeset -n larray=$1 ”定義了局部變數 larray,它是 foo 的的第一個參數的名字引用;也可以使用“ nameref larray=$1 ”得到相同的效果。
array=(1 2 3) function foo {typeset -n larray=$1 # larray是形參;typeset i for i in ${larray[*]} do echo $i done # 對形參 larray 做賦值操作,也就改變了實參 larray[0]=3; larray[1]=2; larray[2]=1; } |
運行 foo,將數組 array 作為參數
> foo array # array 是實參 1 2 3 > echo ${array[*]} # array 確實被 foo 改變了 3 2 1 |
複合變數
複合變數提供了類似於高級語言中結構的功能。
以下 ksh 語句使用複合變數定義了 desk 變數,它有三個域 name,id 和 price 。
desk=( typeset name=yijia integer id=1 float price=340.5 ) |
使用 ${desk.name} 來引用 desk 的 name 域
> echo ${desk.name} yijia |
將複合變數和間接變數引用相結合就能用 ksh93 實現教科書上線性鏈表等標準數據結構。
以下例子給出長度為 2 的一個線性鏈表,讀者可以用類似方法模仿樹的實現。
注意,我們稱 next 為指針,僅是借用了 c 語言指針的說法,它和 c 中的指針在實現上是不一樣的,但是概念類似,即都是屬於間接訪問這個類型。
#!/bin/ksh # /tmp/link.sh second=( # 複合變數 second,next 指針為空 data=1 next=null ) first=( # 複合變數 first,next 指針為 second data=2 next=second ) p=first # 將指針 p 初始化為 first while [[ $p != "null" ]] # 如果指針 p 為空,退出循環 do eval data=\${${p}.data}; echo "data=${data}"; # 取出和列印元素 data eval p=\${${p}.next}; echo "p=$p"; # 將 p 指向下一個元素 done > /tmp/link.sh # 執行 link.sh data=2 p=second data=1 p=null |
更方便的字元串操作
程序員日常工作中是經常遇到的操作之一就是字元串操作,ksh93 自然不會放過這方面的增強。
表 1 總結了 ksh93 在字元串處理方面的加強,假設 string 等於 abc123abc 。
功能 | 語法 | 樣例 |
求起始位置為 index 的子串 | ${param:offset} | > echo ${string:3} 123abc |
求起始位置為 index 和長度 num 的子串 | ${param:offset:num} | > echo ${string:1:3} bc1 |
替換第一個出現的 pattern為 repl | ${parm/pattern/repl} | > echo ${string/abc/def} def123abc |
替換所有出現的 pattern 為 repl | ${parm//pattern/repl} | > echo ${string//abc/def} def123def |
替換開頭的 pattern | ${parm/#pattern/repl} | > echo ${string/#abc/def} def123abc |
替換結尾的 pattern | ${parm/%pattern/repl} | > echo ${string/%abc/def} abc123def |
[火星人 ] Ksh93 高級特性簡介已經有909次圍觀