AWK快速入门教程
最近看到安装开源软件的相关脚本,其中大量用到AWK相关内容。本文介绍AWK的基础知识及典型用法、结合示例进行说明,方便备忘查询。了解awk基础知识将大大提高命令行上操作文本文件的能力。awk有几种不同的实现。我们将使用awk的GNU实现,它被称为gawk。在大多数Linux系统上,awk解释器只是gawk的符号链接。
记录和字段
Awk可以处理文本数据文件和流。输入数据分为记录和字段。Awk每次操作一条记录,直到到达输入的末尾。记录由一个称为记录分隔符的字符分隔。默认的记录分隔符是换行符,这意味着文本数据中的每一行都是一条记录。可以使用RS变量设置新的记录分隔符。
记录由字段分隔符分隔的字段组成。默认情况下,字段由空格分隔,包括一个或多个制表符、空格和换行符。
每个记录中的字段由美元符号($)引用,后面跟着以1开头的字段号。第一个字段用$1表示,第二个字段用 2 表示,以此类推。最后一个字段也可以用特殊变量 2表示,以此类推。最后一个字段也可以用特殊变量 2表示,以此类推。最后一个字段也可以用特殊变量NF来引用。可以用$0引用整个记录。
下面是如何引用记录和字段的可视化表示:
tmpfs 788M 1.8M 786M 1% /run/lock
/dev/sda1 234G 191G 31G 87% /
|-------| |--| |--| |--| |-| |--------|
$1 $2 $3 $4 $5 $6 ($NF) --> fields
|-----------------------------------------|
$0 --> record
AWK 程序
要用awk处理文本,需要编写一个程序,告诉命令该做什么。该程序由一系列规则和用户定义的函数组成。每个规则包含一个模式和操作对。规则之间用换行符或分号(;)分隔。通常,awk程序是这样的:
pattern { action }
pattern { action }
...
当awk处理数据时,如果模式与记录匹配,它就对该记录执行指定的操作。当规则没有模式时,匹配所有记录(行)。
awk动作用大括号({})括起来,由语句组成。每个语句指定要执行的动作。一个动作可以有多个语句,用换行符或分号(;)分隔。如果规则没有动作,则默认打印整个记录。
Awk支持不同类型的语句,包括表达式、条件、输入、输出语句等等。最常见的awk语句有:
exit
- 停止执行整个程序并结束.next
- 停止处理当前记录并移至输入数据的下一条记录.print
- 打印记录、字段、变量以及自定义文本.printf
- 对输出格式进行更多的控制,类似C语言的printf
.
在编写awk程序时,在井号(#)之后直到行尾的所有内容都被认为是注释。可以使用延续字符反斜杠()将长行分成多行。
执行AWK程序
awk程序可以以几种方式运行。如果程序很短很简单,可以直接在命令行上传递给awk解释器:
awk 'program' input-file...
当在命令行上运行程序时,它应该用单引号(")括起来,这样shell就不会解释该程序。
如果程序又大又复杂,最好把它放在一个文件中,然后使用-f选项将文件传递给awk命令:
awk -f program-file input-file...
在下面的例子中,我们将使用一个名为“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中的模式控制是否应该执行关联的操作。Awk支持不同类型的模式,包括正则表达式、关系表达式、范围和特殊表达式模式。当规则没有模式时,将匹配每个输入记录。下面是一个只包含一个动作的规则示例:
awk '{ print $3 }' teams.txt
程序将打印每条记录的第三个字段:
60
58
51
49
48
正则表达式
正则表达式或正则表达式是匹配一组字符串的模式。Awk正则表达式模式用斜杠(//)括起来:
/regex pattern/ { action }
最基本的例子是文字字符或字符串匹配。例如,要显示每条包含“0.5”的记录的第一个字段,您可以运行以下命令:
awk '/0.5/ { print $1 }' teams.txt
# 输出结果
Celtics
Pacers
模式可以是任何类型的扩展正则表达式。下面是一个示例,如果记录以两个或两个以上数字开头,则打印第一个字段:
awk '/^[0-9][0-9]/ { print $1 }' teams.txt
## 输出
76ers
关系表达式
关系表达式模式通常用于匹配特定字段或变量的内容。
默认情况下,将根据记录匹配正则表达式模式。要将正则表达式与字段匹配,请指定字段并对模式使用“包含”比较运算符(~)。
例如,要打印第二个字段包含“ia”的每条记录的第一个字段,您可以输入:
awk '$2 ~ /ia/ { print $1 }' teams.txt
# output
76ers
Pacers
要匹配不包含给定模式的字段,请使用!~操作符:
awk '$2 !~ /ia/ { print $1 }' teams.txt
# output
Bucks
Raptors
Celtics
可以比较字符串或数字的关系,如大于、小于、等于等。下面的命令打印第三个字段大于50的所有记录的第一个字段:
awk '$3 > 50 { print $1 }' teams.txt
# output
Bucks
Raptors
76ers
范围模式
范围模式有两个逗号分隔的独立模式组成:
pattern1, pattern2
从匹配第一个模式的记录开始的所有记录,直到匹配第二个模式的记录。下面是一个示例,它将打印所有记录的第一个字段,从包含“Raptors”的记录开始,直到包含“Celtics”的记录:
awk '/Raptors/,/Celtics/ { print $1 }' teams.txt
# output
Raptors
76ers
Celtics
该模式也支持关系表达式。下面的命令将打印从第四个字段等于32开始的所有记录,直到第四个字段等于33的记录:
awk '$4 == 31, $4 == 33 { print $0 }' teams.txt
# output
76ers Philadelphia 51 31 0.622
Celtics Boston 49 33 0.598
范围模式不能与其他模式表达式组合。
特殊表达式模式
Awk包括以下特殊模式:
BEGIN -用于在处理记录之前执行操作。
END -用于在记录处理后执行操作。
BEGIN模式通常用于设置变量,END模式用于处理记录(如计算)中的数据。
下面的示例将打印“Start Processing”。,然后打印每条记录的第三个字段,最后打印“End Processing”:
awk 'BEGIN { print "Start Processing." }; { print $3 }; END { print "End Processing." }' teams.txt
# output
Start Processing
60
58
51
49
48
End Processing.
如果程序只有BEGIN模式,则执行操作,而不处理输入。如果程序只有END模式,则在执行规则操作之前处理输入。
awk的Gnu版本还包括两个更特殊的模式BEGINFILE和ENDFILE,它们允许您在处理文件时执行操作。
组合模式
Awk允许您使用逻辑与操作符(&&)和逻辑或操作符(||)组合两个或多个模式。
下面是一个使用&&运算符打印第三个字段大于50且第四个字段小于30的记录的第一个字段的示例:
awk '$3 > 50 && $4 < 30 { print $1 }' teams.txt
# output
Bucks
Raptors
内置变量
Awk有许多内置变量,其中包含有用的信息,并允许您控制程序的处理方式。下面是一些最常见的内置变量:
NF
- 记录的字段数.NR
- 当前记录编号.FILENAME
- 当前正在处理的输入文件的名称.FS
- 字段分隔符.RS
- 记录分隔符.OFS
- 输出字段分隔符.ORS
- 输出记录分隔符.
下面是一个显示如何打印文件名和行数(记录)的示例:
awk 'END { print "File", FILENAME, "contains", NR, "lines." }' teams.txt
#output
File teams.txt contains 5 lines.
AWK中的变量可以在程序中的任何一行设置。要为整个程序定义一个变量,请将其放在BEGIN模式中。
改变记录和字段的分隔符
字段分隔符的默认值是任意数量的空格或制表符。它可以通过在FS变量中设置来更改。
例如,将字段分隔符设置为。你可以用:
awk 'BEGIN { FS = "." } { print $1 }' teams.txt
#output
Bucks Milwaukee 60 22 0
Raptors Toronto 58 24 0
76ers Philadelphia 51 31 0
Celtics Boston 49 33 0
Pacers Indiana 48 34 0
字段分隔符也可以设置为多个字符:
awk 'BEGIN { FS = ".." } { print $1 }' teams.txt
当在命令行上运行awk一行程序时,您还可以使用-F选项来更改字段分隔符:
awk -F "." '{ print $1 }' teams.txt
默认情况下,记录分隔符是一个换行符,可以使用RS变量进行更改。
下面是一个演示如何将记录分隔符更改为。的示例:
awk 'BEGIN { RS = "." } { print $1 }' teams.txt
# output
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操作被括在大括号({})中,并在模式匹配时执行。一个操作可以有零条或多条语句。多条语句按照它们出现的顺序执行,并且必须用换行符或分号(;)分隔。
awk中支持几种类型的操作语句:
- 表达式,如变量赋值、算术运算符、自增和自减运算符。
- 控制语句,用于控制程序的流程(if、for、while、switch等)。
- 输出语句,如print和printf。
- 复合语句,用于组合其他语句。
- 输入语句,用于控制输入的处理。
- 删除语句,用于删除数组元素。
print语句可能是最常用的awk语句。它打印文本、记录、字段和变量的格式化输出。
打印多个项目时,需要用逗号分隔。下面是一个例子:
awk '{ print $1, $3, $5 }' teams.txt
# output
Bucks 60 0.732
Raptors 58 0.707
76ers 51 0.622
Celtics 49 0.598
Pacers 48 0.585
如果不带参数使用print,则默认打印$0。打印当前记录。
要打印自定义文本,必须用双引号对文本进行引用:
awk '{ print "The first field:", $1}' teams.txt
# output
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" }'
# output
First line
Second line
Third line
printf语句提供了对输出格式控制。下面是插入行号的示例:
awk '{ printf "%3d. %s\n", NR, $0 }' teams.txt
# output
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
# output
266
下面是另一个例子,展示了如何使用表达式和控制语句来打印从1到5的数字的平方:
awk 'BEGIN { i = 1; while (i < 6) { print "Square of", i, "is", i*i; ++i } }'
#output
Square of 1 is 1
Square of 2 is 4
Square of 3 is 9
Square of 4 is 16
Square of 5 is 25
像上面这样的单行命令更难理解和维护。当编写较长的程序时,你应该创建一个单独的程序文件:
# prg.awk
BEGIN {
i = 1
while (i < 6) {
print "Square of", i, "is", i*i;
++i
}
}
通过将文件名传递给awk解释器来运行程序:
awk -f prg.awk
你也可以通过使用shebang指令和设置awk解释器来将awk程序作为可执行文件运行:
prg.awk 文件内容:
#!/usr/bin/awk -f
BEGIN {
i = 1
while (i < 6) {
print "Square of", i, "is", i*i;
++i
}
}
保存文件并设置可执行:
chmod +x prg.awk
# 现在直接执行
./prg.awk
在Awk程序中使用Shell变量
如果在shell脚本中使用awk命令,那么很可能需要向awk程序传递一个shell变量。一种选择是用双引号而不是单引号括起程序,并替换程序中的变量。然而,这个选项将使您的awk程序更加复杂,因为您需要转义awk变量。
在awk程序中使用shell变量的推荐方法是将shell变量赋值给awk变量。下面是一个例子:
$ num=51
$ awk -v n="$num" 'BEGIN {print n}'
# output
51
总结
Awk是最强大的文本操作工具之一,本文仅仅介绍了awk编程语言的皮毛。要了解更多关于awk的信息,请查看官方Gawk文档。参考文档:Awk Command in Linux with Examples | Linuxize