Ksh93 高级特性简介

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 。

表 1. 更强的字符串处理
功能语法样例
求起始位置为 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

注:上述的 pattern 是正则表达式


一个例子

问题 : 给定 m 和 n, 假设 m>=n, 从 m 中取 n 的排列可能有 P(m,n) 个 , 写一个 program 列出所有的排列可能

解题思路:将所有排列可能表示为一棵树,遍历此树,当到达叶子节点时,就得到了排列的一个解。图一给出了 P(4,4) 的某个分支,这个分支包含了以 2 打头的所有排列共 6 个。

图一 . P(4,4) 树的一个分支
P(4,4)树的一个分支

代码实现:见附件permutation.sh,它使用了递归和 ksh93 的两个功能:nameref 和 c 风格的 for 循环 .


结语:

除了以上所列功能外,ksh93 的高级功能还有 Discipline functions,这项功能对 self debug 时特别有用,鉴于篇幅,这里就不再详细描述了,有兴趣的读者可以参考 ksh93 手册。

总之,ksh93 的这些高级功能提供相对于其他 shell 的竞争优势,从而让 ksh 在 UNIX 下继续保持旺

盛的生命力。

声明:本文仅代表作者个人之观点,不代表 IBM 公司之观点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值