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

Posted xcywt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Linux命令行与shell脚本编程大全》第二十二章 gawk进阶相关的知识,希望对你有一定的参考价值。

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

22.1 使用变量

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

内建变量和自定义变量

 

22.1.1 内建变量

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

 

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

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

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

 

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

 

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

变量

描述

FIELDWIDTHS

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

FS

输入字段分隔符

RS

输入记录分隔符

OFS

输出字段分隔符

ORS

输出记录分隔符

 

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

实例:

[email protected]:~/shell/22zhang$ cat data1

data11,data12,data13,data14

data21,data22,data23,data24

data31,data32,data33,data34

data41,data42,data43,data44

data51,data52,data53,data54

[email protected]:~/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

[email protected]:~/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

[email protected]:~/shell/22zhang$

 

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

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

 

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

例子:

[email protected]:~/shell/22zhang$ cat data2

1005.3246782.37

115-2.343324.08

05828.3452433.1

[email protected]:~/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

[email protected]:~/shell/22zhang$

 

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

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

例子:

[email protected]:~/shell/22zhang$ cat data3

kobe bryant

24 Los Lakers

Los, road34

99038

 

Paul Gaoso

15 los Lakers

Los, road 38

23123

[email protected]:~/shell/22zhang$ gawk ‘BEGIN{FS="\n";RS=""} {print $1, $4}‘ data3

kobe bryant 99038

Paul Gaoso 23123

[email protected]:~/shell/22zhang$ gawk ‘BEGIN{FS="\n";RS=""} {print $1, $2}‘ data3

kobe bryant 24 Los Lakers

Paul Gaoso 15 los Lakers

[email protected]:~/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:

[email protected]:~/shell/22zhang$ gawk ‘BEGIN{print ARGC,ARGV[1]}‘ data2

2 data2

[email protected]:~/shell/22zhang$ gawk ‘BEGIN{print ENVIRON["HOME"]}‘

/home/xcy

[email protected]:~/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

[email protected]:~/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变量则含有已处理过的记录总数

[email protected]:~/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

[email protected]:~/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

[email protected]:~/shell/22zhang$

 

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

 

注意:

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

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

 

 

22.1.2自定义变量

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

1.在脚本中给变量赋值

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

例子:

[email protected]:~/shell/22zhang$ gawk ‘

> BEGIN{

> test="hahaha, i am test"

> print test}‘

hahaha, i am test

[email protected]:~/shell/22zhang$ gawk ‘

BEGIN{

test="hahaha, i am test"

print test

> test=156

> print test

> }‘

hahaha, i am test

156

[email protected]:~/shell/22zhang$ gawk ‘

> BEGIN{

> x=4

> x=x*3+4

> print x

> }‘

16

[email protected]:~/shell/22zhang$

 

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

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

[email protected]:~/shell/22zhang$ cat script

BEGIN{FS=","}

{print $n}

[email protected]:~/shell/22zhang$ gawk -f script n=3 data1

data13

data23

data33

data43

data53

[email protected]:~/shell/22zhang$

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

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

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

 

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

[email protected]:~/shell/22zhang$ cat script2

BEGIN{print "The starting value is",n; FS=","}

{print $n}

[email protected]:~/shell/22zhang$ gawk -v n=4 -f script2 data1

The starting value is 4

data14

data24

data34

data44

data54

[email protected]:~/shell/22zhang$

 

22.2 处理数组

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

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

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

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

 

22.2.1 定义数组变量

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

var[index]=element

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

例子:

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

[email protected]:~/shell/22zhang$ gawk ‘                     

BEGIN{

nba["kobe"]="bryant"

nba["cp3"]="paul"

print nba["kobe"]

print nba["cp3"]

}‘

bryant

paul

# 还可以进行数学运算。

[email protected]:~/shell/22zhang$ gawk ‘

> BEGIN{

> arr[1]=99

> arr[2]=77

> total=arr[1] + arr[2]

> print "total =",total

> }‘

total = 176

[email protected]:~/shell/22zhang$

 

 

22.2.2 遍历数组变量

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

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

for (var in array)

{

  statements

}

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

[email protected]:~/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]

}

}

[email protected]:~/shell/22zhang$ gawk -f script3

Index: a  - Value: hahah

Index: b  - Value: 2

Index: c  - Value: yutong keche

Index: d  - Value: 4

[email protected]:~/shell/22zhang$

 

22.2.3删除数组变量

格式如下:

delete array[index]

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

比如:

[email protected]:~/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]

}

}

[email protected]:~/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

[email protected]:~/shell/22zhang$

 

22.3 使用模式

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

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

 

22.3.1 正则表达式

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

 

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

[email protected]:~/shell/22zhang$ cat script5

BEGIN{FS=","}

/11/{print $1, $2}

[email protected]:~/shell/22zhang$ gawk -f script5 data1

data11 data12

[email protected]:~/shell/22zhang$

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

 

 

22.3.2 匹配操作符

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

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

$1 ~ /^data/

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

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

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

例子2:

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

[email protected]:~/shell/22zhang$ cat data1

data11,data12,data13,data14

data21,data22,data23,data24

data31,data32,data33,data34

data41,data42,data43,data44

data51,data52,data53,data54

[email protected]:~/shell/22zhang$ gawk ‘BEGIN{FS=","} $2 ~ /^data2/{print $1, $3}‘ data1   data21 data23

[email protected]:~/shell/22zhang$ gawk ‘BEGIN{FS=","} $2 !~ /^data2/{print $1, $3}‘ data1  // 这里还可以取反,匹配第二个字段不以data2开头的记录。加个感叹号

data11 data13

data31 data33

data41 data43

data51 data53

[email protected]:~/shell/22zhang$

 

例子3:

[email protected]:~/shell/22zhang$ gawk ‘BEGIN{FS=":"} $1 ~ /^xcy/{print $1,":" $NF}‘ /etc/passwd

xcy :/bin/bash

[email protected]:~/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语言的差不多

例子:

[email protected]:~/shell/22zhang$ cat data4

3

5

34

467

1

[email protected]:~/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 "

         }

}

[email protected]:~/shell/22zhang$ gawk -f ifscript data4

step 2 $1 == 3

step 3

$1 > 29

34

$1 > 29

467

step 3

[email protected]:~/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语言一样

 

例子:

[email protected]:~/shell/22zhang$ cat data5

100 110 120

170 180 190

300 310 320

[email protected]:~/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

}

[email protected]:~/shell/22zhang$ gawk -f script6 data5

i= 2

Average: 70

i= 2

Average: 116.667

i= 2

Average: 203.333

[email protected]:~/shell/22zhang$

 

 

 

22.4.3 do-while语句

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

do

{

  statement

} while(condition)

 

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

例子:

[email protected]:~/shell/22zhang$ cat script7

{

total=0

i=1

do

{

         total += $i

         i++

} while(total < 300)

print "total:",total,"i=",i

}

[email protected]:~/shell/22zhang$ gawk -f script7 data5

total: 330 i= 4

total: 350 i= 3

total: 300 i= 2

[email protected]:~/shell/22zhang$

 

22.4.4 for语句

支持C风格的for循环:

例子:

[email protected]:~/shell/22zhang$ cat script8

{

total=0

for(i=1; i<4; i++)

{

         total += $i

}

avg=total/3

print "Total:",total,"Average:",avg

}

[email protected]:~/shell/22zhang$ gawk -f script8 data5

Total: 330 Average: 110

Total: 540 Average: 180

Total: 930 Average: 310

[email protected]:~/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的例子:

[email protected]:~/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]

}

}

[email protected]:~/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

[email protected]:~/shell/22zhang$

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

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

 

下面是split的例子:

[email protected]:~/shell/22zhang$ cat data1

data11,data12,data13,data14

data21,data22,data23,data24

data31,data32,data33,data34

data41,data42,data43,data44

data51,data52,data53,data54

[email protected]:~/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]

}

[email protected]:~/shell/22zhang$ gawk -f script10 data1

 

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

count表示字段总数

22.6.3 时间函数

函数

描述

mktime(datadpace)

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

strftime(format [,timestamp])

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

systime()

返回当前时间的时间戳

 

例子:

[email protected]:~/shell/22zhang$ cat script11

BEGIN{

date=systime()

day=strftime("%A, %B %d, %Y",date)

print day

}

[email protected]:~/shell/22zhang$ gawk -f script11

星期六, 十一月 25, 2017

[email protected]:~/shell/22zhang$

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

否则报错

[email protected]:~/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代码块)。

实例:

[email protected]:~/shell/22zhang$ cat data3

kobe bryant

24 Los Lakers

Los, road34

99038

 

Paul Gaoso

15 los Lakers

Los, road 38

23123

[email protected]:~/shell/22zhang$ cat fun1

function myprint()

{

         print "This is myprint() +++"

         printf "%-16s - %s\n", $1,$4

}

BEGIN{

FS="\n"

RS=""

}

{

myprint()

}

[email protected]:~/shell/22zhang$ gawk -f fun1 data3

This is myprint() +++

kobe bryant      - 99038

This is myprint() +++

Paul Gaoso       - 23123

[email protected]:~/shell/22zhang$

 

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

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

 

22.7.3 创建函数库

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

步骤:

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

[email protected]:~/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)就可以在脚本中使用啦

[email protected]:~/shell/22zhang$ cat usefunlib

BEGIN{

FS="\n"

RS=""

}

{

myprint()

}

[email protected]:~/shell/22zhang$ gawk -f funlib -f usefunlib data3

kobe bryant      - 99038

Paul Gaoso       - 23123

[email protected]:~/shell/22zhang$

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

 

22.8 实例

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

[email protected]:~/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

 

下面是脚本:

[email protected]:~/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相加,就是总成绩了。最后求平均值

 

这里是运行情况:

[email protected]:~/shell/22zhang$ ./bowling.sh

Total for team1 is 656 The avgarge is 109.333

Total for team2 is 545 The avgarge is 90.8333

以上是关于《Linux命令行与shell脚本编程大全》第二十二章 gawk进阶的主要内容,如果未能解决你的问题,请参考以下文章

《Linux命令行与shell脚本编程大全》第二十六章 一些有意思的脚本

《Linux命令行与shell脚本编程大全》第二十五章 创建与数据库web及电子邮件相关的脚本

《Linux命令行与shell脚本编程大全》23章24章

更新完毕Linux命令行与Shell脚本编程大全(第3版)读书笔记21-26章

linux命令行与shell脚本编程大全---bash shell命令

《Linux命令行与Shell脚本编程大全第2版.布卢姆》pdf