gawk 使用总结

gawk 简介

gawk程序是Unix中的原始awk程序的GNU版本,它能提供一个类编程环境来修改和重新组织文件中的数据,让流编辑迈上一个新的台阶。在gawk编程语言中,你可以做下面的事情:

  • 定义变量来保存数据;
  • 使用算术和字符串操作符来处理数据;
  • 使用结构化编程概念(比如if-then语句和循环)来为数据处理增加处理逻辑;
  • 通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。

gawk程序的报告生成能力通常用来从大文本文件中提取数据元素,并将它们格式化成可读的报告。

gawk命令格式

gawk options program file
gawk选项:

选 项 描 述
-F fs 指定行中划分数据字段的字段分隔符
-f file 从指定的文件中读取程序
-v var=value 定义gawk程序中的一个变量及其默认值
-mf N 指定要处理的数据文件中的最大字段数
-mr N 指定数据文件中的最大数据行数
-W keyword 指定gawk的兼容模式或警告等级

从命令行读取程序脚本

gawk程序脚本用一对花括号来定义,必须将脚本命令放到两个花括号({})中。
gawk命令行假定脚本是单个文本字符串,必须将脚本放到单引号中。如:
$ gawk '{print "Hello World!"}'
如果没有指定文件名,默认从STDIN接收数据。
sed一样,gawk会针对数据流中的每行文本执行程序脚本。
Ctrl+D会在bash中产生一个EOF字符,终止该gawk程序并返回到命令行界面提示符下。

使用数据字段变量

gawk的主要特性之一是其处理文本文件中数据的能力。它会自动给一行中的每个数据元素分配一个变量。
默认情况下,gawk会将如下变量分配给它在文本行中发现的数据字段:

  • $0代表整个文本行;
  • $1代表文本行中的第1个数据字段;
  • $2代表文本行中的第2个数据字段;
  • $n代表文本行中的第n个数据字段。

gawk在读取一行文本时,会用预定义的字段分隔符划分每个数据字段,默认的字段分隔符是任意的空白字符(例如空格或制表符),用-F选项自定义字段分隔符。如:

$ cat data2.txt
One line of test text.
Two lines of test text.
$
$ gawk '{print $1}' data2.txt
One
Two
$
$ gawk -F: '{print $1}' /etc/passwd
root
bin
...

在程序脚本中使用多个命令

gawk使用分号 ; 分隔多条命令:

$ echo "My name is Rich" | gawk '{$4="Christine"; print $0}'
My name is Christine
$

#也可以用次提示符一次一行地输入程序脚本命令。
$ gawk '{
> $4="Christine"
> print $0}'
My name is Rich

My name is Christine

从文件中读取程序

跟sed编辑器一样,gawk编辑器允许将程序存储到文件中,然后再在命令行中引用。

$ cat script2.gawk
{print $1 "'s home directory is " $6}
$
#在程序文件中指定多条命令,一条命令放一行即可,不需要用分号。
$ cat script3.gawk
{
text = "'s home directory is "
print $1 text $6
}

$ gawk -F: -f script2.gawk /etc/passwd  #gawk -F: -f script3.gawk /etc/passwd
root's home directory is /root
bin's home directory is /bin
[...]

在处理数据前后运行脚本

gawk在读取数据前执行BEGIN关键字后指定的程序脚本,用另一个脚本区域定义数据处理脚本,在END关键字后指定读完数据后执行的程序脚本。 多段脚本仍然被认为是gawk命令行中的一个文本字符串,需要相应地加上单引号。

$ cat data3.txt
Line 1
Line 2
Line 3
$
$ gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}
> END {print "End of File"}' data3.txt
The data3 File Contents:
Line 1
Line 2
Line 3
End of File

gawk进阶

使用变量

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

  • 内建变量
  • 自定义变量

内建变量

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

字段和记录分隔符变量

gawk数据字段和记录变量,可以在 BEGIN 脚本区域设置,值要加双引号:

变 量 描 述
FIELDWIDTHS 由空格分隔的一列数字,定义了每个数据字段确切宽度
FS 输入字段分隔符,默认是空格
RS 输入记录分隔符,默认是换行符
OFS 输出字段分隔符,默认是空格
ORS 输出记录分隔符,默认是换行符

一旦设置了FIELDWIDTH变量,gawk就会忽略FS变量,并根据提供的字段宽度来计算字段。

$ cat data1b
1005.3247596.37
115-2.349194.00
05810.1298100.1
$ gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1b
100 5.324 75 96.37
115 -2.34 91 94.00
058 10.12 98 100.1
$

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

数据变量

gawk提供了其他内建变量来帮助了解数据发生了什么变化,并提取shell环境的信息。

变 量 描 述
ARGC 当前命令行参数个数
ARGIND 当前文件在ARGV中的位置
ARGV 包含命令行参数的数组
CONVFMT 数字的转换格式(参见printf语句),默认值为%.6 g
ENVIRON 当前shell环境变量及其值组成的关联数组
ERRNO 当读取或关闭输入文件发生错误时的系统错误号
FILENAME 用作gawk输入数据的数据文件的文件名
FNR 当前数据文件中的数据行数
IGNORECASE 设成非零值时,忽略gawk命令中出现的字符串的字符大小写
NF 数据文件中的字段总数
NR 已处理的输入记录数
OFMT 数字的输出格式,默认值为%.6 g
RLENGTH match函数所匹配的子字符串的长度
RSTART match函数所匹配的子字符串的起始位置

gawk并不会将程序脚本当成命令行参数的一部分。

$ gawk 'BEGIN{print ARGC,ARGV[0],ARGV[1]}' data1
2 awk data1

说明:跟shell变量不同,在脚本中引用gawk变量时,变量名前不加美元符。

ENVIRON变量使用关联数组来提取shell环境变量。数组索引中的文本是shell环境变量名,而数组的值则是shell环境变量的值。

$ gawk '
> BEGIN{
> print ENVIRON["HOME"]
> print ENVIRON["PATH"]
> }'
/home/rich
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin
$

gawk使用FNRNFNR跟踪数据字段和记录,NF可以指定记录中的最后一个数据字段。

$ gawk 'BEGIN{FS=":"; OFS=":"} {print $1,$NF}' /etc/passwd
rich:/bin/bash
[...]

FNRNR变量虽然类似,但又略有不同。FNR变量含有当前数据文件中已处理过的记录数,NR变量则含有已处理过的记录总数

$ gawk 'BEGIN{FS=","}{print $1,"FNR="FNR}' data1 data1
data11 FNR=1
data21 FNR=2
data31 FNR=3
data11 FNR=1
data21 FNR=2
data31 FNR=3
$
$ gawk '
> BEGIN {FS=","}
> {print $1,"FNR="FNR,"NR="NR}
> END{print "There were",NR,"records processed"}' data1 data1
data11 FNR=1 NR=1
data21 FNR=2 NR=2
data31 FNR=3 NR=3
data11 FNR=1 NR=4
data21 FNR=2 NR=5
data31 FNR=3 NR=6
There were 6 records processed

结论:如果只使用一个数据文件作为输入, FNR和NR的值是相同的;如果使用多个数据文件作为输入, FNR的值会在处理每个数据文件时被重置,而NR的值则会继续计数直到处理完所有的数据文件。

说明:在shell脚本中使用gawk时,应该将不同的gawk命令放到不同的行,这样会比较容 易阅读和理解,不要在shell脚本中将所有的命令都塞到同一行。还有,如果你发现在不同 的shell脚本中用到了同样的gawk脚本,记着将这段gawk脚本放到一个单独的文件中,并 用-f参数来在shell脚本中引用它

自定义变量

gawk允许自定义变量,变量名可以是任意数目的字母、数字和下划线,但不能以数字开头。 变量名区分大小写

在脚本中给变量赋值

在gawk程序中给变量赋值跟在shell脚本中赋值类似,都用赋值语句。变量可以保存数值或文本值。赋值语句还可以包含数学算式来处理数字值, gawk编程语言包含了用来处理数字值的标准算数操作符。其中包括求余符号(%)和幂运算符号(^**)。

$ gawk '
> BEGIN{
> testing="This is a test"
> print testing
> testing=45
> print testing
> }'
This is a test
45
$
$ gawk 'BEGIN{x=4; x= x * 2 + 3; print x}'
11
$
在命令行上给变量赋值

也可以用gawk命令行来给程序中的变量赋值。这允许你在正常的代码之外赋值,即时改变 变量的值。下面的例子使用命令行变量来显示文件中特定数据字段。

$ cat script1
BEGIN{FS=","}
{print $n}
$ gawk -f script1 n=2 data1
data12
data22
data32
$ gawk -f script1 n=3 data1
data13
data23
data33
$

使用命令行参数来定义变量值会有一个问题。在你设置了变量后,这个值在代码的BEGIN部分不可用。

$ cat script2
BEGIN{print "The starting value is",n; FS=","}
{print $n}
$ gawk -f script2 n=3 data1
The starting value is
data13
data23
data33

可以用-v命令行参数来解决这个问题。它允许你在BEGIN代码之前设定变量。在命令行上,-v命令行参数必须放在脚本代码之前。

$ gawk -v n=3 -f script2 data1
The starting value is 3
data13
data23
data33

处理数组

gawk编程语言使用关联数组提供数组功能。关联数组跟数字数组不同之处在于它的索引值可以是任意文本字符串。每个索引字符串都必须能 够唯一地标识出赋给它的数据元素。跟其他语言的散列表和字典是同一个概念。

定义数组变量

可以用标准赋值语句来定义数组变量。数组变量赋值的格式如下:
var[index] = element
在引用数组变量时,必须包含索引值来提取相应的数据元素值。

$ gawk 'BEGIN{
> capital["Illinois"] = "Springfield"
> print capital["Illinois"]
> }'
Springfield
$
#在引用数组变量时,会得到数据元素的值。数据元素值是数字值时也一样。
$ gawk 'BEGIN{
> var[1] = 34
> var[2] = 3
> total = var[1] + var[2]
> print total
> }'
37
$

遍历数组变量

在gawk中遍历一个关联数组,可以用for语句的一种特殊形式。

for (var in array)
{
statements
}

这个for语句会在每次循环时将关联数组array的下一个索引值赋给变量var,然后执行一遍statements。 索引值不会按任何特定顺序返回。

$ gawk 'BEGIN{
> var["a"] = 1
> var["g"] = 2
> var["m"] = 3
> var["u"] = 4
> for (test in var)
> {
> print "Index:",test," - Value:",var[test]
> }
> }'
Index: u - Value: 4
Index: m - Value: 3
Index: a - Value: 1
Index: g - Value: 2

删除数组变量

从关联数组中删除数组索引要用一个特殊的命令。

delete array[index]
删除命令会从数组中删除关联索引值和相关的数据元素值。

$ gawk 'BEGIN{
> var["a"] = 1
> var["g"] = 2
> for (test in var)
> {
> print "Index:",test," - Value:",var[test]
> }
> delete var["g"]
> print "---"
> for (test in var)
> print "Index:",test," - Value:",var[test]
> }'
Index: a - Value: 1
Index: g - Value: 2
---
Index: a - Value: 1

使用模式

前面已经介绍了两种特殊的模式(BEGINEND)在实践中的应用,可以创建其他模式在数据流中出现匹配数据时执行一些命令。

正则表达式

可以用基础正则表达式(BRE)或扩展正则表达式(ERE)来选择程序脚本作用在数据流中的哪些行上。
在使用正则表达式时,正则表达式必须出现在它要控制的程序脚本的左花括号前。

$ gawk 'BEGIN{FS=","} /11/{print $1}' data1 gawk程序会用正则表达式对记录中所有的数据字段进行匹配,包括字段分隔符。

$ gawk 'BEGIN{FS=","} /,d/{print $1}' data1
data11
data21
data31

这个例子使用正则表达式匹配了用作字段分隔符的逗号。它可能会造成如下问题:当试图匹配某个数据字段中的特定数据时,这些数据又出现在其他数据字段中。如果需要用正则表达式匹配某个特定的数据实例,应该使用匹配操作符。

匹配操作符

匹配操作符(matching operator)允许将正则表达式限定在记录中的特定数据字段。 匹配操作符是波浪线(~)。可以指定匹配操作符、数据字段变量以及要匹配的正则表达式。

$1 ~ /^data/ 这个表达式会过滤出第一个字段以文本data开头的所有记录。例子:

$ gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1
data21,data22,data23,data24,data25
$

可以用!符号来排除正则表达式的匹配。

$1 !~ /expression/
如果记录中没有找到匹配正则表达式的文本,程序脚本就会作用到记录数据。

$ gawk –F: '$1 !~ /rich/{print $1,$NF}' /etc/passwd
root /bin/bash
daemon /bin/sh
bin /bin/sh
sys /bin/sh
--- output truncated ---

数学表达式

除了正则表达式,可以在匹配模式中用数学表达式。这个功能在匹配数据字段中的数字值时非常方便。例如:

$ gawk -F: '$4 == 0{print $1}' /etc/passwd
root
sync

可以使用任何常见的数学比较表达式。

  • x == y:值x等于y。
  • x <= y:值x小于等于y。
  • x < y:值x小于y。
  • x >= y:值x大于等于y。
  • x > y:值x大于y。

也可以对文本数据使用表达式,但表达式必须完全匹配。数据必须跟模式严格匹配。

结构化命令

gawk编程语言支持常见的结构化编程命令。

if 语句

gawk支持标准的if-then-else格式的if语句。格式:

if (condition)
statement1
#也可以将它放在一行上,像这样:
if (condition) statement1
if (condition) statement1; else statement2

如果需要在if语句中执行多条语句,就必须用花括号将它们括起来。
在单行上使用else子句,必须在if语句部分之后使用分号。

注意,不能弄混if语句的花括号和用来表示程序脚本开始和结束的花括号。如果弄混了, gawk程序能够发现丢失了花括号,并产生一条错误消息。

$ gawk '{
> if ($1 > 20)
> {
> x = $1 * 2
> print x
> } else
> {
> x = $1 / 2
> print x
> }}' data4
5
2.5
6.5
100
68

while 语句

while语句为gawk程序提供了一个基本的循环功能,格式:

while (condition)
{
statements
}

while循环允许遍历一组数据,并检查迭代的结束条件。如果在计算中必须使用每条记录中的多个数据值,这个功能能帮得上忙。gawk编程语言支持在while循环中使用break语句和continue语句,允许你从循环中跳出。

$ cat data5
130 120 135
160 113 140
145 170 215

$ gawk '{
> total = 0
> i = 1
> while (i < 4)
> {
> total += $i
> if (i == 2)
> break
> i++
> }
> avg = total / 2
> print "The average of the first two data elements is:",avg
> }' data5
The average of the first two data elements is: 125
The average of the first two data elements is: 136.5
The average of the first two data elements is: 157.5

do-while 语句

do-while语句类似于while语句,但会在检查条件语句之前执行命令。下面是do-while语 句的格式。

do
{
statements
} while (condition)

这种格式保证了语句会在条件被求值之前至少执行一次。当需要在求值条件前执行语句时, 这个特性非常方便。

$ gawk '{
> total = 0
> i = 1
> do
> {
> total += $i
> i++
> } while (total < 150)
> print total }' data5
250
160
315

for 语句

gawk编程语言支持C风格的for循环。 for( variable assignment; condition; iteration process)

$ gawk '{
> total = 0
> for (i = 1; i < 4; i++)
> {
> total += $i
> }
> avg = total / 3
> print "Average:",avg
> }' data5
Average: 128.333
Average: 137.667
Average: 176.667

格式化打印

print语句只能控制输出字段分隔符(OFS)。gawk与c相同,提供printf来格式化输出,格式:

printf "format string", var1, var2 . . .
格式化指定符采用如下格式:

%[modifier]control-letter
control-letter是一个单字符代码,用于指明显示什么类型的数据,如下表。而modifier则定义了可选的格式化特性。

控制字母 描 述
c 将一个数作为ASCII字符显示
d 显示一个整数值
i 显示一个整数值(跟d一样)
e 用科学计数法显示一个数
f 显示一个浮点值
g 用科学计数法或浮点数显示(选择较短的格式)
o 显示一个八进制值
s 显示一个文本字符串
x 显示一个十六进制值
X 显示一个十六进制值,但用大写字母A~F

除了控制字母外,还有3种修饰符可以用来进一步控制输出。

  • width:指定了输出字段最小宽度的数字值。如果输出短于这个值,printf会将文本右 对齐,并用空格进行填充。如果输出比指定的宽度还要长,则按照实际的长度输出。
  • prec:这是一个数字值,指定了浮点数中小数点后面位数,或者文本字符串中显示的最大字符数。
  • -(减号):指明在向格式化空间中放入数据时采用左对齐而不是右对齐。

例如:
printf "%-16s %s\n", $1, $4 指定输出宽度为16个字符,并且左对齐
printf "Average: %5.1f\n",avg 指定浮点值近似到小数点后一位

注意,你需要在printf命令的末尾手动添加换行符来生成新行。没添加的话,printf命令会继续在同一行打印后续输出。

内建函数

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

数学函数

gawk数学函数

函 数 描 述
atan2(x, y) x/y的反正切,x和y以弧度为单位
cos(x) x的余弦,x以弧度为单位
exp(x) x的指数函数
int(x) x的整数部分,取靠近零一侧的值
log(x) x的自然对数
rand() 比0大比1小的随机浮点值
sin(x) x的正弦,x以弧度为单位
sqrt(x) x的平方根
srand(x) 为计算随机数指定一个种子值

产生较大整数随机数的常见方法是用rand()函数和int()函数创建一个算法。
x = int(10 * rand()) 返回一个0~9(包括0和9)的随机整数值。
在使用一些数学函数时要小心,因为gawk语言对于它能够处理的数值有一个限定区间。如果超出了这个区间,就会得到一条错误消息。

$ gawk 'BEGIN{x=exp(100); print x}'
26881171418161356094253400435962903554686976
$ gawk 'BEGIN{x=exp(1000); print x}'
gawk: warning: exp argument 1000 is out of range
inf

第一个例子会计算e的100次幂,虽然数值很大,但尚在系统的区间内。第二个例子尝试计算 e的1000次幂,已经超出了系统的数值区间,所以就生成了一条错误消息。
除了标准数学函数外,gawk还支持一些按位操作数据的函数。

函 数 描 述
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提供了一些用来处理字符串值的函数:

  • 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(如果提供了的话)来匹配正则表达式r。如果找到了,就全部替换成字符串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中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处匹配
  • substr(s, i [,n]) 返回s中从索引值i开始的n个字符组成的子字符串。如果未提供n,则返回s剩下的部分
  • tolower(s) 将s中的所有字符转换成小写
  • toupper(s) 将s中的所有字符转换成大写

asort和asorti函数是新加入的gawk函数,允许你基于数据元素值(asort)或索引值(asorti)对数组变量进行排序。如:

$ gawk 'BEGIN{
> var["a"] = 1
> var["g"] = 2
> var["m"] = 3
> var["u"] = 4
> asort(var, test)
> for (i in test)
> print "Index:",i," - value:",test[i]
> }'
Index: 4 - value: 4
Index: 1 - value: 1
Index: 2 - value: 2
Index: 3 - value: 3

新数组test含有排序后的原数组的数据元素,但索引值现在变为表明正确顺序的数字值了。
split函数是将数据字段放到数组中以供进一步处理的好办法。

$ gawk 'BEGIN{ FS=","}{
> split($0, var)
> print var[1], var[5]
> }' data1
data11 data15
data21 data25
data31 data35

新数组使用连续数字作为数组索引,从含有第一个数据字段的索引值1开始。

时间函数

gawk包含一些函数来帮助处理时间值:

  • mktime(datespec) 将一个按YYYY MM DD HH MM SS [DST]格式指定的日期转换成时间戳值
  • strftime(format[,timestamp]) 将当前时间的时间戳或timestamp(如果提供了的话)转化为格式化日期(采用shell 函数date()的格式)
  • systime() 返回当前时间的时间戳

时间函数常用来处理日志文件,而日志文件则常含有需要进行比较的日期。通过将日期的文 本表示形式转换成epoch时间(自1970-01-01 00:00:00 UTC到现在的秒数),可以轻松地比较日期。

$ gawk 'BEGIN{
> date = systime()
> day = strftime("%A, %B %d, %Y", date)
> print day
> }'
Friday, December 26, 2014

该例用systime函数从系统获取当前的epoch时间戳,然后用strftime函数将它转换成用户 可读的格式,转换过程中使用了shell命令date的日期格式化字符。

自定义函数

除了gawk中的内建函数,还可以在gawk程序中创建自定义函数。本节将会介绍如何在gawk 程序中定义和使用自定义函数。

定义函数

用function关键字自定义的函数:

function name([variables])
{
statements
}

function myrand(limit)
{
return int(limit * rand())
}

x = myrand(100)

返回值可以是变量,或者是最终能计算出值的算式。返回值可以赋给变量。

使用自定义函数

在定义函数时,它必须出现在所有代码块之前(包括BEGIN代码块)。乍一看可能有点怪异, 但它有助于将函数代码与gawk程序的其他部分分开。

$ gawk '
> function myprint()
> {
> printf "%-16s - %s\n", $1, $4
> }
> BEGIN{FS="\n"; RS=""}
> {
> myprint()
> }' data2
Riley Mullen - (312)555-1234
Frank Williams - (317)555-9876
Haley Snell - (313)555-4938

创建函数库

gawk可以将多个函数放到一个库文件中,这样就能在所有的gawk程序中使用了。
首先,你需要创建一个存储所有gawk函数的文件。

$ cat funclib
function myprint()
{
printf "%-16s - %s\n", $1, $4
}
function myrand(limit)
{
return int(limit * rand())
}
function printthird()
{
print $3
}

funclib文件含有三个函数定义。需要使用-f命令行参数来使用它们。很遗憾,不能将-f命令 行参数和内联gawk脚本放到一起使用,不过可以在同一个命令行中使用多个-f参数。 因此,要使用库,只要创建一个含有你的gawk程序的文件,然后在命令行上同时指定库文件和程序文件就行了。

$ cat script4
BEGIN{ FS="\n"; RS=""}
{
myprint()
}
$ gawk -f funclib -f script4 data2
Riley Mullen - (312)555-1234
Frank Williams - (317)555-9876
Haley Snell - (313)555-4938

实例

举例,有一个数据文件,包含了两支队伍(每队两名选手)的保龄球比赛得分情况。 每位选手都有三场比赛的成绩,这些成绩都保存在数据文件中,每位选手由位于第二列的队 名来标识。下面的脚本对每队的成绩进行了排序,并计算了总分和平均分。

$ cat scores.txt
Rich Blum,team1,100,115,95
Barbara Blum,team1,110,115,100
Christine Bresnahan,team2,120,115,118
Tim Bresnahan,team2,125,112,116
$
$ cat bowling.sh
#!/bin/bash
for team in $(gawk –F, '{print $2}' scores.txt | uniq)
do
gawk –v team=$team 'BEGIN{FS=","; total=0}
{
if ($2==team)
{
total += $3 + $4 + $5;
}
}
END {
avg = total / 6;
print "Total for", team, "is", total, ",the average is",avg
}' scores.txt
done
$
$ ./bowling.sh
Total for team1 is 635, the average is 105.833
Total for team2 is 706, the average is 117.667