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主程序文件名 数据文件名,这样,以前编写的函数程序就可以使用了,而不必重复编写这个函数了。