awk 中除了函数的参数列(Argument List)上的参数(Arguments)外,所有变量无论在什么地方出现,均被视为全局变量。全局变量的生命周期持续到程序结束。全局变量不论在function外还是function内都可以使用,只要变量名称相同,所使用的就是同一个变量。但是递归函数会调用会调用到函数本身,所以编写这里函数是需要特别注意。 例如:编辑一个awk脚本程序,内容如下:[root@myfreelinux pub]# cat argument.awk#!/bin/awk -fBEGIN{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.awkInside the function: arg1=36,x=35,y=46,z=55Return 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/bashawk ‘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.awkplease 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主程序文件名 数据文件名,这样,以前编写的函数程序就可以使用了,而不必重复编写这个函数了。