《Linux命令行与shell脚本编程大全》第二十二章 gawk进阶

gawk是一门功能丰富的编程语言,你可以通过它所提供的各种特性来编写好几程序处理数据。 

22.1 使用变量

gawk编程语言支持两种不同类型的变量:

内建变量和自定义变量

22.1.1 内建变量

gawk程序使用内建变量来引用程序数据里的一些特殊功能

1.字段和记录分隔符变量

数据字段变量:允许你使用美元符和字段在该记录中的位置值来引用记录对应的字段。

要引用第一个字段就用变量$1,第二个就用$2,….以此类推。

数据字段是由分隔符来划定的。默认字段分隔符是一个空白字符,也就是空格或者制表符。

有一组内建变量用于控制gawk如何处理输入输出数据中的字段和记录,见下表:

变量

描述

FIELDWIDTHS

有空格分隔的一列数字,定义每个数据字段的确切宽度

FS

输入字段分隔符

RS

输入记录分隔符

OFS

输出字段分隔符

ORS

输出记录分隔符

1)print命令会自动将OFS变量的值放置在输出中的每个字段间。

实例:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data1 data11,data12,data13,data14 data21,data22,data23,data24 data31,data32,data33,data34 data41,data42,data43,data44 data51,data52,data53,data54 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS=","; OFS="-"} {print $1,$2,$3}' data1 data11-data12-data13 data21-data22-data23 data31-data32-data33 data41-data42-data43 data51-data52-data53 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS=","; OFS="<-->"} {print $1,$2,$3}' data1 data11<-->data12<-->data13 data21<-->data22<-->data23 data31<-->data32<-->data33 data41<-->data42<-->data43 data51<-->data52<-->data53 xcy@xcy-virtual-machine:~/shell/22zhang$

2) FIELDWIDTHS变量允许你不依靠字段分割符来读取记录。一旦这是了FILEDWIDTFS变量,gawk就会忽略FS变量。

警告:一旦设定了FIELDWIDTHS变量的值,就不能再改变了。这种方法并不适用于变长的字段

有写数据没有指定分隔符,而是放在特定的列,这时候就可以用FIELDWIDTHS了:

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data2 1005.3246782.37 115-2.343324.08 05828.3452433.1 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"} {print $1,$2,$3,$4}' data2 100 5.324 67 82.37 115 -2.34 33 24.08 058 28.34 52 433.1 xcy@xcy-virtual-machine:~/shell/22zhang$

3)RS和ORS定义了gawk程序如何处理数据流中的字段。默认这两个都是换行符

默认的RS表明,输入数据流中的每行新文本就是一条新记录

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data3 kobe bryant 24 Los Lakers Los, road34 99038 Paul Gaoso 15 los Lakers Los, road 38 23123 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS="\n";RS=""} {print $1, $4}' data3 kobe bryant 99038 Paul Gaoso 23123 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS="\n";RS=""} {print $1, $2}' data3 kobe bryant 24 Los Lakers Paul Gaoso 15 los Lakers xcy@xcy-virtual-machine:~/shell/22zhang$

上面的例子中,4行才是一条记录,所以指定FS=”\n”

每行只是一个字段。

如何判断一个新的数据行的开始:解决方法计算RS变量设为空。然后在数据记录之间留一个空白行。gawk会把每个空白行当做一个记录分隔符。

说明:

默认的字段分隔符是空格,记录分割符是换行符

上面的例子把字段分割符改成了换行符,记录分隔符编程了空白行(RS=””)

2. 数据变量

还有一些其他的内建变量:

变量

描述

ARGC

当前命令行参数个数

ARGIND

当前文件在ARGV的位置

ARGV

包含命令行参数的数组

CONVFMT

数字的转换格式,模式是%.6 g

ENVIRON

当前shell环境变量及其值组成的关联数组

ERRNO

当读取或关闭文件发生错误时的系统错误号

FILENAME

用作输入数据的数据文件的文件名

FNR

当前数据文件的数据行数

IGNORECASE

设成非零值,忽略gawk命令中出现的字符串的字符大小写

NF

数据文件中的字段总数

NR

已处理的输入记录数

OFMT

数字的输出格式,默认值%.6 g

RLENGTH

由match函数所匹配的字符串的长度

RSTART

由match函数所匹配的字符串的起始位置

实例1:

xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{print ARGC,ARGV[1]}' data2 2 data2 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{print ENVIRON["HOME"]}' /home/xcy xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{print ENVIRON["HOME"]; print ENVIRON["PATH"]}' /home/xcy /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sbin/:/usr/bin: /usr/sbin:/home/xcy/Bt_A7/Bt_A7/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin xcy@xcy-virtual-machine:~/shell/22zhang$

 ENVIRON[“HOME”] 从系统中提取HOME环境变量的值。

例子2:

当要在gawk程序中跟踪数据字段和记录时,变量FNR,NF和NR就非常方便了。

NF变量可以在你不知道具体位置的情况下指定记录中的最后一个数据字段:

$gawk ‘BEGIN{FS=”:”; OFS=”:”} {print $1, $NF}’ /etc/passwd

假设NF为7,那么相当于是$7。打印最后一个字段

例子3:

FNR变量含有当前数据文件中已处理过的记录数

NR变量则含有已处理过的记录总数

xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS=","} {print $1,"FNR="FNR}' data1 data11 FNR=1 data21 FNR=2 data31 FNR=3 data41 FNR=4 data51 FNR=5 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS=","} {print $1,"FNR="FNR, "NR="NR} END{print "There were ",NR," recordes"}' data1 data1 data11 FNR=1 NR=1 data21 FNR=2 NR=2 data31 FNR=3 NR=3 data41 FNR=4 NR=4 data51 FNR=5 NR=5 data11 FNR=1 NR=6 data21 FNR=2 NR=7 data31 FNR=3 NR=8 data41 FNR=4 NR=9 data51 FNR=5 NR=10 There were  10  recordes xcy@xcy-virtual-machine:~/shell/22zhang$

当处理第2个文件时,FNR又被置成1了,但是NR还是继续增加的。

注意:

1)在shell脚本中使用gawk时,应该将gawk的命令放到不同的行,便于理解和阅读

2)如果在不同的shell脚本中使用了相同的gawk脚本,应该把gawk放在一个单独的文件中。再用-f参数去引用它。

22.1.2自定义变量

变量名可以是字母下划线开头,还可以有数字。并且变量名区分大小写

1.在脚本中给变量赋值

可以对变量进行修改,可以进行数学运算

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ gawk ' > BEGIN{ > test="hahaha, i am test" > print test}' hahaha, i am test xcy@xcy-virtual-machine:~/shell/22zhang$ gawk ' BEGIN{ test="hahaha, i am test" print test > test=156 > print test > }' hahaha, i am test 156 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk ' > BEGIN{ > x=4 > x=x*3+4 > print x > }' 16 xcy@xcy-virtual-machine:~/shell/22zhang$

2. 在命令行上给变量赋值

也可以用gawk命令行来给程序中的变量赋值。这允许你在正常的代码之外赋值。

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script BEGIN{FS=","} {print $n} xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script n=3 data1 data13 data23 data33 data43 data53 xcy@xcy-virtual-machine:~/shell/22zhang$

上面可以给n进行赋值,改变脚本的行为。

这样可以在不改变脚本代码的情况下就能改变脚本的行为

上面这样存在的问题是设置的变量在代码的BEGIN部分不可用

解决方法,用-v参数。它允许你在BEGIN代码之前设定变量,要放在脚本代码之前。

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script2 BEGIN{print "The starting value is",n; FS=","} {print $n} xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -v n=4 -f script2 data1 The starting value is 4 data14 data24 data34 data44 data54 xcy@xcy-virtual-machine:~/shell/22zhang$

22.2 处理数组

gawk编程语言使用关联数组提供数组功能

关联数组跟数字数组不同之处在于它的索引值可以是任意文本字符串。

不需要用连续的数字来标识数组元素。关联数组用各种字符串来引用值

每个索引字符串都必须能够唯一标识赋给它的数据元素

22.2.1 定义数组变量

用标准赋值语句来定义数组变量。格式如下:

var[index]=element

var是变量名,index是关联数组的索引值 element是数据元素值

例子:

这里要加双引号,数字不用加,字符串需要加

xcy@xcy-virtual-machine:~/shell/22zhang$ gawk '                      BEGIN{ nba["kobe"]="bryant" nba["cp3"]="paul" print nba["kobe"] print nba["cp3"] }' bryant paul # 还可以进行数学运算。 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk ' > BEGIN{ > arr[1]=99 > arr[2]=77 > total=arr[1] + arr[2] > print "total =",total > }' total = 176 xcy@xcy-virtual-machine:~/shell/22zhang$

22.2.2 遍历数组变量

关联数组的索引可以是任何东西

遍历数组可以用for语句的一种特殊形式:

for (var in array)

{

  statements

}

这个for语句会在每次循环时都将关联数组array的下一个索引值赋值给变量var,然后执行一遍statements

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script3 BEGIN{ var["a"]="hahah" var["b"]=2 var["c"]="yutong keche" var["d"]=4 for (test in var) {          print "Index:",test," - Value:",var[test] } } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script3 Index: a  - Value: hahah Index: b  - Value: 2 Index: c  - Value: yutong keche Index: d  - Value: 4 xcy@xcy-virtual-machine:~/shell/22zhang$

22.2.3删除数组变量

格式如下:

delete array[index]

删除以后就没办法再用它来提取元素值了。

比如:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script4 BEGIN{ var["a"]="hahah" var["b"]=2 var["c"]="yutong keche" for (test in var) {          print "old: Index:",test," - Value:",var[test] } print "Now,delete array:" delete var["c"] for (test in var) {          print "new: Index:",test," - Value:",var[test] } } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script4 old: Index: a  - Value: hahah old: Index: b  - Value: 2 old: Index: c  - Value: yutong keche Now,delete array: new: Index: a  - Value: hahah new: Index: b  - Value: 2 xcy@xcy-virtual-machine:~/shell/22zhang$

22.3 使用模式

gawk支持多种类型的匹配模式来过滤数据记录。

BEGIN和END关键字用来读取数据流之前或之后执行命令的特殊模式

22.3.1 正则表达式

可以用基础正则表达式(BRE)或扩展正则表达式(ERE)来选择程序脚本作用在数据流中的哪些行上。

使用正则表达式时,正则表达式必须出现在它要控制的程序脚本的左花括号前。

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script5 BEGIN{FS=","} /11/{print $1, $2} xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script5 data1 data11 data12 xcy@xcy-virtual-machine:~/shell/22zhang$

正则表达式/11/匹配了字段中含有字符串11的记录。

22.3.2 匹配操作符

匹配操作符允许将正则表达式限定在记录中的特定数据字段。匹配操作符是~。

可以指定匹配操作符,数据字段变量以及要匹配的正则表达式

$1 ~ /^data/

$1变量代表记录中的第一个数据字段。

上面的例子会过滤出以data开头的所有记录。

取反: $1 !~ /^data1/   匹配第一个字段不以data1开头的记录

例子2:

// 匹配第2个字段为data2开头的记录,并且打印第1和第3个字段。$2表示第2个字段

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data1 data11,data12,data13,data14 data21,data22,data23,data24 data31,data32,data33,data34 data41,data42,data43,data44 data51,data52,data53,data54 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $1, $3}' data1   data21 data23 xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS=","} $2 !~ /^data2/{print $1, $3}' data1  // 这里还可以取反,匹配第二个字段不以data2开头的记录。加个感叹号 data11 data13 data31 data33 data41 data43 data51 data53 xcy@xcy-virtual-machine:~/shell/22zhang$

例子3:

xcy@xcy-virtual-machine:~/shell/22zhang$ gawk 'BEGIN{FS=":"} $1 ~ /^xcy/{print $1,":" $NF}' /etc/passwd xcy :/bin/bash xcy@xcy-virtual-machine:~/shell/22zhang$

例子4:! 用来排除正则表达式中的匹配

$ gawk -F: '$1 !~ /^xcy|^root/{print $1, ":" $NF}' /etc/passwd

-F 用来指定主句字段的分隔符

上面表明过滤第一个字段不以xcy开头,或不以root开头。

22.3.3 数学表达式

还可以在匹配模式中用数学表达式。

例子:想显示所有属于root用户组(组ID为0)的系统用户

$gawk –F: ‘$4 == 0{print $1}’ /etc/passwd

还可以用任何常见的数学比较表达式: ==  <=  >=  >  <

匹配字符串:注意这时候是完全匹配

$gawk –F, ‘$1==”data” {print $1}’ data1

第一个字段必须是data,而不是包含data

22.4 结构化命令

22.4.1 if语句

给if语句定义一个求值的条件,并将其用圆括号括起来。

条件为真在if后面的语句就会执行。

还可以接上else。和C语言的差不多

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data4 3 5 34 467 1 xcy@xcy-virtual-machine:~/shell/22zhang$ cat ifscript {          if ($1 > 29)          {                    print "$1 > 29"  # 多条命令需要用{}括起来                    print $1          }          else if($1 == 3)           {                    print "step 2 $1 == 3"          }                 else          {                    print "step 3 "          } } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f ifscript data4 step 2 $1 == 3 step 3 $1 > 29 34 $1 > 29 467 step 3 xcy@xcy-virtual-machine:~/shell/22zhang$

还可以在单行上使用else子句,这样就需要在if后面接上分号;

$ gawk '{if($1 == 3) print $1" == 3 "; else print $1,"!= 3"}' data4

22.4.2 while 语句

基本格式:

while (condition)

{

  statement

}

while里面还可以放break和continue。用起来跟C语言一样

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data5 100 110 120 170 180 190 300 310 320 xcy@xcy-virtual-machine:~/shell/22zhang$ cat script6 { total=0 i=1 while(i < 4) {          total += $i          i++          if(i==3)          {                    break                    #continue          }          print "i=", i } avg=total/3 print "Average:",avg } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script6 data5 i= 2 Average: 70 i= 2 Average: 116.667 i= 2 Average: 203.333 xcy@xcy-virtual-machine:~/shell/22zhang$

22.4.3 do-while语句

和while语句类似,但是会在检查条件语句之前执行命令。格式如下:

do

{

  statement

} while(condition)

这种格式保证了语句在条件被求值之前至少执行一次

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script7 { total=0 i=1 do {          total += $i          i++ } while(total < 300) print "total:",total,"i=",i } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script7 data5 total: 330 i= 4 total: 350 i= 3 total: 300 i= 2 xcy@xcy-virtual-machine:~/shell/22zhang$

22.4.4 for语句

支持C风格的for循环:

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script8 { total=0 for(i=1; i<4; i++) {          total += $i } avg=total/3 print "Total:",total,"Average:",avg } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script8 data5 Total: 330 Average: 110 Total: 540 Average: 180 Total: 930 Average: 310 xcy@xcy-virtual-machine:~/shell/22zhang$

22.5 格式化打印

print打印在如何显示数据上并未提供多少控制。

下面介绍一个格式化打印命令,printf,和C语言的那个有点类似:

printf “format string” ,var1,var2…

前面也是格式化命令。跟C语言很像:

1)

%c 输出字符, %d 整数值, %i 整数值,%e 用科学计数法显示数

%f 浮点数,%g 科学计数法或浮点数显示(较短的)

%o 八进制,%s 字符串

%x 十六进制小写,%X 十六进制大写

2)

还有三种修饰符可以用来进一步控制输出

width:指定输出字段最小宽度的数字值。实际比这短,则会补充空格,否则按正常输出

prec:指定浮点数中小数点后面的位数。或者文本字符串中显示的最大字符数

-(减号):指明在格式化空间中放入数据时采用左对齐,而不是右对齐

例子:

$ cat data3 kobe bryant 24 Los Lakers Los, road34 99038 Paul Gaoso 15 los Lakers Los, road 38 23123 $ gawk 'BEGIN{FS="\n"; RS=""} {printf "%s %s\n", $1,$2}' data3  #正常输出 kobe bryant 24 Los Lakers Paul Gaoso 15 los Lakers $ gawk 'BEGIN{FS="\n"; RS=""} {printf "%16s %s\n", $1,$2}' data3  #指定输出字段最小宽度      kobe bryant 24 Los Lakers       Paul Gaoso 15 los Lakers $ gawk 'BEGIN{FS="\n"; RS=""} {printf "%-16s %s\n", $1,$2}' data3  #指定左对齐 kobe bryant      24 Los Lakers Paul Gaoso       15 los Lakers

还可以指定浮点数格式

… {printf “%5.1f\n”, avg} …

占5位,小数点后只显示一位。

22.6 内建函数

gawk提供了不少内建的函数,可以进行常见的数学 字符串以及时间函数运算

22.6.1 数学函数

函数

描述

atan2(x,y)

x/y的反正切,x y以弧度为单位

cos(x)

X的余弦 x以弧度为单位

exp(x)

X的指数函数

int(x)

X的整数部分,取靠近零一侧的值

log(x)

X的自然对数

rand(x)

比0大比1小的随机浮点数

sin(x)

正弦,x以弧度为单位

sqrt(x)

X的平方根

srand(x)

为计算随机数指定一个种子值

and(v1,v2)

执行v1和v2的按位与运算

compl(val)

执行val的补运算

lshift(val,count)

Val的值左移count位

or(v1,v2)

V1和v2的按位或运算

rshift(val,count)

Val右移count位

xor(v1,v2)

V1和v2的异或运算

例子:

$ gawk 'BEGIN{x=rand(); print "x =",x}' $gawk 'BEGIN{x=int(-7.6); print "x =",x}' $ gawk 'BEGIN{x=sin(1.57); print "x =",x}' $ gawk 'BEGIN{x=int(10*rand()); print "x =",x}' $ gawk 'BEGIN{x=and(1,2); print "x =",x}' $ gawk 'BEGIN{x=lshift(1,2); print "x =",x}' $ gawk 'BEGIN{x=xor(1,2); print "x =",x}'

22.6.2 字符串函数

函数

描述

asort(s [,d])

将数组s按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。另外如果指定了d,则排序后的数组会存储在数组d中。

asorti(s [,d])

将数组s按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字所以来表明排序顺序。若指定了d,排序后是数组会存在d中

gensub(r,s,h [,t])

查找变量$0或目标字符串t(若提供的话)来匹配正则表达式r。 如果h是一个以g或G开头的字符串,就用s替换掉匹配的文本。 如果h是数字,它表示要替换掉的第h处r匹配的地方

gsub(r,s [,t])

查找变量$0或目标字符串t(若提供的话)来匹配正则表达式。 如果找到了就全部替换成字符串s

index(s,t)

返回字符串t在字符串s中的索引值。如果没找到返回0

length([s])

返回字符串s的长度,如果没有指定的话返回$0的长度

match(s, r [,a])

返回字符串s中正则表达式r出现位置的索引。若指定数组a,则会存储s中匹配正则表达式的那部分

split(s, a [,r])

将s用FS字符或正则表达式r(若指定的话)分开放到数组a中。返回字段总数

sprintf(format,variables)

用提供的format和variables返回一个类似于printf输出的字符串

sub(r,s [,t])

在变量$0或目标字符串t中查找正则表达式t的匹配。若找到了,就用字符串s替换掉第一处匹配

substr[s,i [,n]]

返回s从索引值i开始的n个字符组成的字符串。若未提供n,则返回s剩下的部分

tolower(s)

全部转小写

toupper(s)

全部转大写

有些用起来比较简单,比如大小写,求长度

$ gawk 'BEGIN{x=length("chong"); print "x =",x}' $ gawk 'BEGIN{x=toupper("chong"); print "x =",x}'

下面是asort的例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script9 BEGIN{ var["a"]=177 var["b"]=9 var["c"]=3 var["d"]=4444 var["e"]=566 asort(var,test) for (i in test) {          print "Index:",i,"-value:",test[i] } } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script9 Index: 4 -value: 566 Index: 5 -value: 4444 Index: 1 -value: 3 Index: 2 -value: 9 Index: 3 -value: 177 xcy@xcy-virtual-machine:~/shell/22zhang$

注意看对var数组的数据元素进行排序了。排序后的数组放在test数组里面了。

索引值被替换成了数字。索引最大的对应数据元素也是最大的。

下面是split的例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data1 data11,data12,data13,data14 data21,data22,data23,data24 data31,data32,data33,data34 data41,data42,data43,data44 data51,data52,data53,data54 xcy@xcy-virtual-machine:~/shell/22zhang$ cat script10 BEGIN{ FS="," } { count=split($0,test) for (i in test) {          print "Index:", i, "-Value:",test[i] } print "count =",count #print test[1], test[5] } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script10 data1

将每一行用FS字符(,)分开,放到了test数组上。再打印数组的数据。

count表示字段总数

22.6.3 时间函数

函数

描述

mktime(datadpace)

将一个按YYYYMMDDHHMMSS[DST]格式指定的日期转成时间戳值

strftime(format [,timestamp])

将当前时间的时间戳或timestamp(若提供的话)转化格式化日期(采用shell函数data()的格式)

systime()

返回当前时间的时间戳

例子:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat script11 BEGIN{ date=systime() day=strftime("%A, %B %d, %Y",date) print day } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script11 星期六, 十一月 25, 2017 xcy@xcy-virtual-machine:~/shell/22zhang$

注意:BEGIN后面的{要挨着BEGIN写,不能换行写。

否则报错

xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f script11

gawk: script11:2: BEGIN 块必须有一个行为部分

22.7 自定义函数

22.7.1 定义函数

必须要用function关键字,格式如下:

function name([variables])

{

  statement

}

函数名必须能够统一标识函数。可以在调用的gawk程序中传给这个函数一个或多个变量

例子:

// 打印记录中的第三个字段

function printthird()

{

  print $3

}

还可以用return返回值。

例子:

function myrand(limit)

{

  return int(limit * rand())

}

用法:

x=myrand(100)

22.7.2 使用自定义函数

定义函数时,它必须出现在所有代码块之前(包括BEGIN代码块)。

实例:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat data3 kobe bryant 24 Los Lakers Los, road34 99038 Paul Gaoso 15 los Lakers Los, road 38 23123 xcy@xcy-virtual-machine:~/shell/22zhang$ cat fun1 function myprint() {          print "This is myprint() +++"          printf "%-16s - %s\n", $1,$4 } BEGIN{ FS="\n" RS="" } { myprint() } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f fun1 data3 This is myprint() +++ kobe bryant      - 99038 This is myprint() +++ Paul Gaoso       - 23123 xcy@xcy-virtual-machine:~/shell/22zhang$

先格式化记录中的第一个和第四个数据字段。再输出

定义了函数就可以在程序的代码中随便使用了

22.7.3 创建函数库

可以将多个函数放到一个库文件中,这样就能在所有的gawk程序中使用了。

步骤:

1)先创建一个存储所有gawk函数的文件

xcy@xcy-virtual-machine:~/shell/22zhang$ cat funlib function mylib() {          print "mylib() +++" } function myprint() {          printf "%-16s - %s\n",$1,$4 } function myrand(limit) {          return int(limit * rand()) } function printthird() {          print $3 }

2)就可以在脚本中使用啦

xcy@xcy-virtual-machine:~/shell/22zhang$ cat usefunlib BEGIN{ FS="\n" RS="" } { myprint() } xcy@xcy-virtual-machine:~/shell/22zhang$ gawk -f funlib -f usefunlib data3 kobe bryant      - 99038 Paul Gaoso       - 23123 xcy@xcy-virtual-machine:~/shell/22zhang$

要引用文件需要使用-f参数。可以在同一命令行中使用多个-f参数。

22.8 实例

假设有一个数据文件,里面有两支队伍每队2个人,每人3次的比赛成绩。要求总成绩和平均成绩:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat scores.txt Rich Blum,team1,100,115,99 Bar Blum,team1,110,118,114 Chr Bre,team2,120,80,90 Tim Bre,team2,125,70,60

下面是脚本:

xcy@xcy-virtual-machine:~/shell/22zhang$ cat bowling.sh #!/bin/bash for team in $(gawk -F, '{print $2}' scores.txt | uniq) do #       echo "team: $team"          gawk -v team=$team 'BEGIN{FS=",";total=0}          { #                print "step1+++"                    if ($2==team)                    {                             total += $3 + $4 + $5;                    }          }          END{                    avg = total / 6;                    print "Total for",team,"is",total,"The avgarge is",avg          }' scores.txt done

脚本分析:

1)注意uniq这个关键字,这里可以排除一样的。for语句是用来筛选队名的。

2)for循环里面,假如队名是team1,那么就先处理team1。会读取所有记录,将队名都为team1的记录的$3 $4 $5相加,就是总成绩了。最后求平均值

这里是运行情况:

xcy@xcy-virtual-machine:~/shell/22zhang$ ./bowling.sh Total for team1 is 656 The avgarge is 109.333 Total for team2 is 545 The avgarge is 90.8333

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏移动开发面面观

快速排序法及优化

17340
来自专栏分布式系统进阶

Librdkafka的基础数据结构 1 --- 队列

两个元素: tqh_first: 指向队列的第一个成员; tqh_last: 存的是队列里的最后一个元素的 next指针的变量地址, 这个二级指针太有用了,...

10820
来自专栏老马说编程

(27) 剖析包装类 (中) / 计算机程序的思维逻辑

本节继续探讨包装类,主要介绍Integer类,下节介绍Character类,Long与Integer类似,就不再单独介绍了,其他类基本已经介绍完了,不再赘述。 ...

227100
来自专栏用户画像

6.2.3 分块查找

分块查找,又称为索引顺序查找,吸收了顺序查找和折半查找各自的优先,既有动态结构,又适于快速查找。

7330
来自专栏java学习

面试题19(关于return的用法)

执行下列代码的输出结果是? public class Demo { public static void main(String args[]) { int...

31140
来自专栏Android机器圈

数据结构与算法----数学应用之一元多项式

PS:上一篇说了线性表的顺序表和链式表表达,该片就写一下应用到现实数学中去,一元多项式的加减。

10720
来自专栏软件开发 -- 分享 互助 成长

数据库的规范化

一、基础概念 实体:现实世界中客观存在并可以被区别的事物。比如“一个学生”、“一本书”、“一门课”等。 属性:教科书上解释为:“实体所具有的某一特性”,由此可见...

18060
来自专栏开发与安全

实现一些字符串操作标准库函数、解决一些字符串问题

一、实现字符串操作标准库函数 (1)、strcpy、strncpy、memmove、memcpy、memset、strlen、strncat 的实现 C++ C...

32790
来自专栏LanceToBigData

JavaProblem之hashCode详解

一、HashCode简介 1.1、什么是Hash和Hash表   要想清楚hashCode就要先清楚知道什么是Hash   1)Hash ? ?  hash是...

20180
来自专栏海天一树

小朋友学数据结构(6):折半查找法

假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键...

11410

扫码关注云+社区

领取腾讯云代金券