awk的使用 第十部分 使用awk编写递归程序的实例

 awk 中除了函数的参数列(Argument List)上的参数(Arguments)外,所有变量无论在什么地方出现,均被视为全局变量。全局变量的生命周期持续到程序结束。全局变量不论在function外还是function内都可以使用,只要变量名称相同,所使用的就是同一个变量。但是递归函数会调用会调用到函数本身,所以编写这里函数是需要特别注意。
     例如:编辑一个awk脚本程序,内容如下:
[root@myfreelinux pub]# cat argument.awk
#!/bin/awk -f
BEGIN{
x=35;
y=45;
test_variable(x)
printf(“Return to main: arg1=%d,x=%d,y=%d,z=%d/n”,arg1,x,y,z)
}
function test_variable(arg1)

{
 arg1++;#arg1是参数列上的参数,是local variable,离开此函数后将消失
 y++;#改变主程序中的变量y
 z=55;#z为该函数中新使用的变量,主程序中的变量z 仍可被使用
 printf(“Inside the function: arg1=%d,x=%d,y=%d,z=%d/n”,arg1,x,y,z);
}
执行以上awk程序,并查看结果如下:
[root@myfreelinux pub]# awk -f argument.awk
Inside the function: arg1=36,x=35,y=46,z=55
Return to main: arg1=0,x=35,y=46,z=55
    由上以上结果可推断出:在自定义的函数内部可以随意使用主程序中的任何变量,在自定义函数内使用的变量(除参数外),在该函数外仍然可以使用。这种特性喜忧搀半,坏处是主程序中的变量不易被保护,特别是递归调用本身,执行子函数时会破坏父函数内的变量。
    一个变通的方法是:在函数的参数列中虚列一些参数。函数执行中使用这些虚列的参数来记录不想被破坏的数据,这样执行子函数时就不会破坏父函数中的参数。此外awk 并不会检查调用函数时所传递的参数个数是否一致。
    例如定义递归函数如下:
    function demo( arg1 )
     { # 最常见的错误例子
         ……………..
      for(i=1; i< 20 ; i++)
     {function(x) # 又呼叫本身。因为i 是global variable,所以执行完该子函数后原函数中的i已经被坏,所以本函数无法正确执行
        ………………}
       ………………..}
    可将上列函数中的i虚列在该函数的参数列上,这样i便是一个局部变量,不会因执行子函数而被破坏。将上列函数修改如下:
    function function( arg1,i )
    {…………….
     for(i=1; i< 20; i++)
      { function(x)#awk不会检查呼叫函数时,所传递的参数个数是否一致
      …………..} }
    $0,$1,…,NF,NR等都是awk的全局变量global variable,在递归函数中如果使用了这些awk的内部变量,可以新建一些局部变量来保存内部变量的值,以免这些内部变量的值遭到破坏。
    例如:要求输入一串数据(各数据间用空白隔开) 然后打印出这些数据的所有可能的排列。使用awk编程如下
[root@myfreelinux pub]# cat sort.awk
#!/bin/bash
awk ‘
BEGIN{
print “please input some word,and each word separate with space:”;
getline;
sort($0,”");
printf(“/n There are %d way to permutation these word/n”,counter);
}
function sort(all_word,buffer,new_all_word,nf,i,j)
{
 $0=all_word; #all_word给$0之后awk将自动进行字段分割,默认使用空格分割
 nf=NF;  #分割后NF是all_word上的单词个数
   if(nf==1) #只有最后一个单词时,
 {
  print buffer all_word;#buffer的内容再加上all_word是完成一次排列的结果
  counter++;
  return;
 }
 #一般情况:每次从all_word中取出一个元素放到buffer中,再用all_word中剩下的元素new_all_word往下进行排列
 else for(i=1;i<=nf;i++)
 {
  $0=all_word;#$0作为全局变量,内容发生改变,所以重新把all_word赋给$0,令awk再做一次字段分割
  new_all_word=”";
  for(j=1;j<=nf;j++)#连接new_all_word
   if(j!=i) new_all_word=new_all_word ” ” $j;
  sort(new_all_word,buffer ” ” $i);
 }
}’
$*
执行该程序,并查看运行结果:
[root@myfreelinux pub]# bash sort.awk
please input some word,and each word separate with space:
my you he
 my you he
 my he you
 you my he
 you he my
 he my you
 he you my

 There are 6 way to permutation these word
    解释说明:某些旧版awk,不允许更改$0的内容,可改用gawk或nawk,也可以使用split() 函数来分割all_word。为避免执行子函数时破坏new_all_word,nf,i,j,所以将这些变量也写在参数列上。这样new_all_word,nf,i,j将被当成局部变量, 不会受到子函数中同名变量的影响。
    在声明函数时,参数列上可以将这些“虚列的参数”与真正用于传递信息的参数间以较长的空白隔开,以便于区别。awk 中要将字符串concatenation(连接)时,直接将两字符串放在一起用空格隔开即可(Implicit Operator)。 
    比如:[root@myfreelinux pub]# awk ‘BEGIN{a=”I”; b=” am”; c=a b ” a student”; print c}’
I am a student
    需要注意c=a b “ a student”,这一句中a,b “ a student”之间要有空格将他们隔开,否则awk把他们当成一个单词了。
   awk编写的函数可以重复使用,比如把函数部分单独编写在一文件中,当需要用到这个函数时使用include,将这个函数文件包含进来,例如: $ awk -f 函数文件名 -f awk主程序文件名 数据文件名,这样,以前编写的函数程序就可以使用了,而不必重复编写这个函数了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值