Awk是一种通用脚本语言,用于高级文本处理的。它主要用作报告和分析工具。与大多数其他程序性编程语言不同。
Awk是数据驱动的,这意味着您必须定义一组针对输入文本要执行的操作。它获取输入数据,对其进行转换,然后将结果发送到标准输出。
awk有几种不同的实现。我们将使用Awk的GNU实现,称为gawk。在大多数Linux发行版可用,awk
命令只gawk
的符号链接。
在本教程的所有示例中,我们将使用teams.txt文件作为awk的输入,teams.txt文件内容如下所示。
Bucks Milwaukee 60 22 0.732
Raptors Toronto 58 24 0.707
76ers Philadelphia 51 31 0.622
Celtics Boston 49 33 0.598
Pacers Indiana 48 34 0.585
记录和字段
Awk可以处理文本数据和流。将输入的数据分为记录和字段。Awk一次对一条记录进行操作,直到达到输入结束为止。
记录由记录分隔符分隔。默认的记录分隔符是换行符,这意味着文本数据中的每一行都是一条记录。可以使用RS
变量来设置记录分的隔符。
记录由多个字段组成,并且使用字段分隔符分隔。默认情况下,字段之间用空格分隔,可以是一个或多个制表符,空格等,你可以使用awk命令的-F
选项指定字段的分隔符。
每条记录中的字段都可以使用美元符号$
后跟字段编号表示,从1开始。第一个字段由$1
表示,第二个字段由$2
表示。
依此类推,最后一个字段也可以用特殊变量$NF
表示。 整个记录可以用$0
表示。
下面可以直观展示记录和字段的关系,也是awk处理文本数据默认使用的记录分隔符,即换行符。字段分隔符是空格符。
tmpfs 788M 1.8M 786M 1% /run/lock
/dev/sda1 234G 191G 31G 87% /
|-------| |--| |--| |--| |-| |--------|
$1 $2 $3 $4 $5 $6 ($NF) --> 字段 $1,$2...字段
|-----------------------------------------|
$0 --> 记录由多个字段组成的单行记录
awk命令
要使用awk
处理文本,需要编写程序来告诉awk命令该做什么。程序由一系列规则和用户定义的函数组成。
每个规则包含模式pattern和操作action的键值对。多个规则使用换行符或分号;
分隔。通常awk程序看起来就像这样pattern { action }
。
当awk
处理数据时,如果模式与记录匹配,awk将会对记录执行指定的操作。当规则没有模式时,所有记录/行都匹配。
awk action必须使用花括号{}
括起来,并由多个语句组成。每个语句指定要执行的操作。
action可以有一个或者多个语句,使用用换行符或分号;
隔开。如果规则中没有action,则默认打印整个记录。
Awk支持不同类型的语句,包括表达式,条件,输入,输出语句等。最常见的awk语句是。
exit
停止执行整个程序并退出。next
停止处理当前记录,并移至输入数据下一个记录。
print
打印记录,字段,变量和自定义文本。printf
使您可以更好地控制输出格式,类似于C和bash的printf
函数。
编写awk程序时,井号#
之后直至行末的所有内容均都被视为注释。 可以使用反斜杠\
将长行分成多行。
运行awk程序
awk程序可以通过多种方式运行。如果程序简短且简单,则可以将其直接通过命令行传递给awk解释器。
在命令行运行awk程序时,应将程序括在单引号''
中,这样可以不会被shell程序解释。这是在命令运行awk程序的语法形式awk 'program' input-file...
。
'program'
是awk要运行的程序,input-file
是输入文件,可以是一个或者多个文件。
如果程序又大又复杂,最好将其放入文件中,并使用-f
选项将文件传递给awk
命令。这是运行awk运行程序文件的语法形式awk -f program-file input-file...
。
program-file
是awk程序的文件,input-file
是输入文件,可以是一个或者多个文件。
awk 'program' input-file...
awk -f program-file input-file...
Awk模式
awk中的模式控制着是否要执行相关联的操作。Awk支持不同类型的模式,包括正则表达式,关系表达式,范围和特殊表达式模式。
当没有模式时,将匹配每个输入的记录。命令awk '{ print $3 }' teams.txt
仅包含操作,没有模式。
程序将打印每条记录的第三个字段$3
,默认字段分隔符是空格,所以以下数值是teams.txt文件的第三列的数据。
awk '{ print $3 }' teams.txt
60
58
51
49
48
正则表达式模式
正则表达式是与一组字符串匹配的模式。Awk正则表达式模式包含在斜杠//
中。这是正则表达式模式语法形式/regex pattern/ { action }
。
模式可以是任何类型的扩展正则表达式。最基本的示例是文字或字符串匹配。
例如命令awk '/0.5/ { print $1 }' teams.txt
仅打印包含0.5记录的第一个字段。
命令awk '/^[0-9][0-9]/ { print $1 }' teams.txt
将会搜索以两个或多个数字开头的记录,并打印第一个字段。
awk '/0.5/ { print $1 }' teams.txt
Celtics
Pacers
awk '/^[0-9][0-9]/ { print $1 }' teams.txt
76ers
关系表达模式
关系表达式模式通常用于匹配指定字段或变量的内容。默认情况下,正则表达式模式与记录进行匹配。
要将正则表达式与字段进行匹配,请指定字段并针对模式使用包含比较运算符约等于号~
。要匹配不包含指定模式的字段,请使用不约等于运算符!~
。
除了约等于和不約等于符号之外,您可以比较字符串或数字之间的关系,例如大于>,小于<,等于=符号。
例如命令awk '$2 ~ /ia/ { print $1 }' teams.txt
将会搜索第二个字段包含ia
的记录并打印第一个字段。
awk '$2 ~ /ia/ { print $1 }' teams.txt
76ers
Pacers
例如命令awk '$2 !~ /ia/ { print $1 }' teams.txt
将会搜索第二个字段不包含ia
的记录并打印第一个字段。
awk '$2 !~ /ia/ { print $1 }' teams.txt
Bucks
Raptors
Celtics
例如命令awk '$3 > 50 { print $1 }' teams.txt
将会搜索三字段大于50的所有记录,并打印第一字段。
awk '$3 > 50 { print $1 }' teams.txt
Bucks
Raptors
76ers
范围模式
范围模式由用逗号分隔的两个模式组成,从匹配第一个模式的记录开始,直到匹配第二个模式的记录停止匹配。
也就是说匹配两个模式之间的记录都会被执行相关的操作。即使中间记录没有匹配模式也将会被执行相关操作。
但有一点值得注意的是范围模式不能与某些模式表达式组合使用。但范围模式可以与关系表达式组合使用。
例如命令awk '/Raptors/,/Celtics/ { print $1 }' teams.txt
将会搜索从包含Raptors的记录开始到包含Celtics记录结束的所有记录。
然后打印两个模式之间所有记录的第一个字段{ print $1 }
。
awk '/Raptors/,/Celtics/ { print $1 }' teams.txt
Raptors
76ers //这个记录没有匹配到两个模式中任意一个,但它在两个模式之间,所以也会打印
Celtics
例如命令awk '$4 == 31, $4 == 33 { print $0 }' teams.txt
组合范围模式和关系表达式。
将会搜索第四个字段等于31记录开始,直到第四个字段等于33的所有记录。然后打印整个记录$0
。
awk '$4 == 31, $4 == 33 { print $0 }' teams.txt
76ers Philadelphia 51 31 0.622
Celtics Boston 49 33 0.598
特殊表达模式
Awk可以使用的特殊模式是。BEGIN
用于在处理记录之前执行的操作。END
用于在处理记录后执行操作。
BEGIN
模式通常用于声明变量,END
模式通常用于处理记录中的数据,例如统计指定字段的总数。
如果程序只有BEGIN
模式,则执行操作,并且不处理输入数据。如果程序只有END
模式,则在执行操作之前先处理输入。
awk的Gnu版本还包含另外两个特殊模式BEGINFILE
和ENDFILE
,它们允许您在处理文件时执行操作。
在下面的示例中将打印Start Processing.
,然后打印每个记录的第三个字段,最后打印End Processing.
。这是一个简单的示例,你也可以用于打印字段的名称。
awk 'BEGIN { print "Start Processing." }; { print $3 }; END { print "End Processing." }' teams.txt
Start Processing
60
58
51
49
48
End Processing.
组合模式
Awk允许您使用逻辑AND运算符&&
和逻辑或运算符||
组合两个或多个模式。
例如命令awk '$3 > 50 && $4 < 30 { print $1 }' teams.txt
使用&&
运算符搜索第三字段大于50而第四字段小于30的记录,然后打印已匹配记录的第一个字段。
awk '$3 > 50 && $4 < 30 { print $1 }' teams.txt
Bucks
Raptors
内置变量
Awk具有许多内置变量,这些变量包含非常有用的信息,并允许您控制程序的处理方式。
这是一些最常见的内置变量。NF
记录中的字段总数。NR
当前记录的编号。FILENAME
当前正在处理文件名称。
FS
字段分隔符。RS
记录分隔符。OFS
输出字段分隔符。ORS
输出记录分隔符。
AWK变量可以在程序的任何行声明。要为整个程序定义变量,请将其放在BEGIN
模式中。
例如命令awk 'END { print "File", FILENAME, "contains", NR, "lines." }' teams.txt
。将会打印打印文件名和行数,即记录总数。
awk 'END { print "File", FILENAME, "contains", NR, "lines." }' teams.txt
File teams.txt contains 5 lines.
更改字段与记录分隔符
字段分隔符的默认是空格符,你也可以指定为任意数量的字符,空格,制表符等任何字符。
要修改字段分隔符。可以在awk程序声明FS
变量来进行修改。也可以使用awk命令的-F
选项更改字段分隔符。
例如命令awk 'BEGIN { FS = "." } { print $1,$2 }' teams.txt
将字段分隔符设置为.
。awk的-F
选项的等价命令是awk -F "." '{ print $1,$2 }' teams.txt
。
awk 'BEGIN { FS = "." } { print $1,$2 }' teams.txt
awk -F "." '{ print $1,$2 }' teams.txt
Bucks Milwaukee 60 22 0 732
Raptors Toronto 58 24 0 707
76ers Philadelphia 51 31 0 622
Celtics Boston 49 33 0 598
Pacers Indiana 48 34 0 585
记录分隔符是换行符,可以通过修改RS
变量进行更改。与字段的分隔符一样你可以指定为任意数量的字符,空格,制表符等任何字符。
例如命令awk 'BEGIN { RS = "." } { print $1 }' teams.txt
将会修改记录分隔符为.
。
awk 'BEGIN { RS = "." } { print $1 }' teams.txt
Bucks Milwaukee 60 22 0
732
Raptors Toronto 58 24 0
707
76ers Philadelphia 51 31 0
622
Celtics Boston 49 33 0
598
Pacers Indiana 48 34 0
585
Awk action操作
Awk action操作括在大括号{}
中,并在模式匹配时执行。一个操作可以有零个或多个语句。
多个语句按照它们出现的先后顺序执行,并且必须使用换行符或分号分隔;
。
awk支持几种类型的语句。表达式,例如变量赋值,算术运算符,增量和减量运算符。
控制语句,用于控制程序的流程if
,for
,while
,switch
。输出语句,例如print
和printf
。
复合语句,可将其他语句分组。输入语句,以控制输入的处理。Deletion语句,删除数组元素。
print
语句可能是最常用的awk语句。它打印文本,记录,字段和变量的格式化输出。打印多个字段时,需要用逗号分隔。
例如命令awk '{ print $1, $3, $5 }' teams.txt
打印的1,3,5字段用空格分隔。如果您不使用逗号,则字段之间没有空格,这些字段是串联在一起的。
awk '{ print $1, $3, $5 }' teams.txt
awk '{ print $1 $3 $5 }' teams.txt
Bucks 60 0.732
Raptors 58 0.707
76ers 51 0.622
Celtics 49 0.598
Pacers 48 0.585
如果没有为print
指定参数,默认是print $0
,将打印当前记录。要打印自定义文本,文本必须用双引号引起来。
例如命令awk '{ print "The first field:", $1}' teams.txt
将会打印自定义文本The first field:
和第一个字段。
awk '{ print "The first field:", $1}' teams.txt
The first field: Bucks
The first field: Raptors
The first field: 76ers
The first field: Celtics
The first field: Pacers
您还可以打印特殊字符,例如换行符。
awk 'BEGIN { print "First line\nSecond line\nThird line" }'
First line
Second line
Third line
printf语句
为了使您可以更好地控制输出格式,你可以使用printf
语句。例如命令awk '{ printf "%3d. %s\n", NR, $0 }' teams.txt
将会为记录插入行号。
NR
变量是当前记录的编号,将会插入到占位符号%3d
,$0
变量表示当前正在处理的记录,将会插入到占位符号%s
。
printf
不会在每条记录后创建换行符,因此还在最后使用\n
换行符,进行对记录的换行。
awk '{ printf "%3d. %s\n", NR, $0 }' teams.txt
1. Bucks Milwaukee 60 22 0.732
2. Raptors Toronto 58 24 0.707
3. 76ers Philadelphia 51 31 0.622
4. Celtics Boston 49 33 0.598
5. Pacers Indiana 48 34 0.585
统计字段总和
命令awk '{ sum += $3 } END { printf "%d\n", sum }' teams.txt
计算记录中第三字段值的总和。
程序{ sum += $3 }
对第三个字段进行累计,END
模式程序{ printf "%d\n", sum }
会将sum
变量插入%d
,\n
是换行符号。
awk '{ sum += $3 } END { printf "%d\n", sum }' teams.txt
266
运行awk文件
这是一个awk命令的示例awk 'BEGIN { i = 1; while (i < 6) { print "Square of", i, "is", i*i; ++i } }'
。
显示了如何使用表达式和控制语句来打印从1到5的数字的平方。
这时单行命令显得更难理解和维护。在编写长且复杂的程序时,您应该创建一个单独的程序文件。
然后使用awk命令的-f
选项指定程序文件,awk
解释器将会运行指定的文件运行程序。
awk -f prg.awk
BEGIN {
i = 1
while (i < 6) {
print "Square of", i, "is", i*i;
++i
}
}
您还可以在awk的程序文件中使用shebang指令设置awk
解释器,程序文件内的代码将会使用awk解释器运行。
当创建awk程序后,保存文件并使用chmod命令使程序文件可执行。这样你就可以直接运行awk程序。
chmod +x prg.awk
./prg.awk
#!/usr/bin/awk -f
BEGIN {
i = 1
while (i < 6) {
print "Square of", i, "is", i*i;
++i
}
}
Awk程序与Shell变量
如果您在Shell程序脚本中使用awk
命令,则很可能需要将Shell程序变量传递给awk程序。
一种选择是用双引号而不是单引号将程序引起来,并在程序中替换变量。但是,此方式会使您的awk程序更加复杂,因为您需要对awk变量进行转义。
在awk程序中使用shell变量的推荐方法是将shell变量分配给awk变量。这是一个例子:
num=51
awk -v n="$num" 'BEGIN {print n}'
51
结论
Awk是最强大的文本处理工具之一。本文几乎没有触及awk编程语言所有知识。要了解awk的更多信息,请查看官方Gawk文档。
如果您有任何问题或反馈,请随时发表评论。