目录
一、awk简介
awk的强大之处在于能生成强大的格式化报告。
数据可以来自标准输入、一个或多个文件,或其它命令的输出。
它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。
它在命令行中使用,但更多是作为脚本来使用。
awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。
awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在linux系统中已把awk链接到gawk
二、awk使用
1、awk的命令格式
Usage: awk [options] -f 'progfile' file ...
Usage: awk [options] 'program' file ...
options:
-F : 指明输入时用到的字段分隔符
-v var=value :自定义变量
program:
PATTERN{ACTION STATEMENTS}
语句之间用分号分隔
2、操作和模式
模式可以是以下任意一个:
/正则表达式/:
使用通配符的扩展集
如,/string/ ,表示匹配以string为字符串的行
关系表达式:
可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较
如$2>$1选择第二个字段比第一个字段长的行
模式匹配表达式:
用运算符~(匹配)和~!(不匹配)
模式,模式:
指定一个行的范围。该语法不能包括BEGIN和END模式
/1/,/10/ 从1到10行
'NR==1,NR==10' ,从1到10行
BEGIN:
让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量
END:
让用户在最后一条输入记录被读取之后发生的动作
操作由一人或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内。
主要有四部份:
变量或数组赋值
输出命令
内置函数
控制流命令
3、awk脚本基本结构
# 一个awk脚本通常由:
# BEGIN语句块
# 能够使用模式匹配的通用语句块
# END语句块3部分组成,这三个部分是可选的。
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
任意一个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中,例如:
awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename
awk "BEGIN{ i=0 } { i++ } END{ print i }" filename
4、awk的工作原理
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
第一步:执行BEGIN{ commands }语句块中的语句;
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕
第三步:当读至输入流末尾时,执行END{ commands }语句块。
BEGIN语句块:
在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块:
在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
pattern语句块:
是通用命令是最重要的部分,它也是可选的。
如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
5、常用使用示例
- 在脚本中使用多个命令
# 使用多个命令,则在每个命令之间加分号
# 冒号进行分割字段,然后把第一个字段替换为“Description:”,最后打印出整行数据
[ec2-user@aws ~]$ awk -F: '{$1="Description:"; print $0}' file
Description: There is a big dog and a little dog in the park
Description: There is a big cat and a little cat in the park
Description: There is a big tiger and a litle tiger in the park
- 从文件中读程序命令
# 如果program程序命令过多,可以单独放在一个文件中,然后从文件中读命令。
# 还是以上面为例,把
{
$1="Description:"
print $0
}
# 单独放在一个文件script1中。再用awk处理脚本时,需要用选项 -f 指定脚本程序的位置
[ec2-user@aws ~]$ awk -F: -f script1 file
Description: There is a big dog and a little dog in the park
Description: There is a big cat and a little cat in the park
Description: There is a big tiger and a litle tiger in the park
- 在处理数据之前运行脚本
# awk默认每次读入一行数据,然后用脚本进行处理。
# 如果想在处理文本之前预处理一些命令,可以用BEGIN关键字指定
[ec2-user@aws ~]$ awk -F: 'BEGIN{print "开始处理..."}{print $2}' file
开始处理...
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park
- 在处理数据后运行脚本
# 用END关键字在处理完所有数据后,再运行善后处理工作
[ec2-user@aws ~]$ awk -F: '{print $2} END{print "处理结束..."}' file
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park
处理结束...
三、在program中使用变量
变量又分为两种形式:awk内置的变量;用户自定义的变量。
1、内置变量
记录分隔符相关变量
- FS :输入字段分隔符
- OFS:输出字段分隔符
- RS:输入记录分割符
- ORS:输出字段分隔符
- FIELDWIDTHS:定义数据字段的宽度
数据分割段相关变量
FILENAME: 当前文件名
NR: 表示所有处理文件已处理的输入记录个数
FNR: 文件的当前记录数
NF: 表示数据文件中数据字段的个数,可以通过$NF获取最后一个数据字段
ARGC: 命令行参数个数
ARGV: 命令行参数数组
$0: 这个变量包含执行过程中当前行的文本内容。
$1: 这个变量包含第一个字段的文本内容。
$2: 这个变量包含第二个字段的文本内容。
示例
- 操作的file文件内容
The dog:There is a big dog and a little dog in the park
The cat:There is a big cat and a little cat in the park
The tiger:There is a big tiger and a litle tiger in the park
- FS用法
# 用FS指定字段分隔符为“:”,然后用“:”把每行数据分割为两段。
[ec2-user@aws ~]$ awk 'BEGIN{FS=":"} {print $1, $2}' file
The dog There is a big dog and a little dog in the park
The cat There is a big cat and a little cat in the park
The tiger There is a big tiger and a litle tiger in the park
OFS用法
# 用FS指定输入字段分隔符“:”后,每行数据分为两个数据段
# 输出时,用OFS指定两个数据字段用“>”拼接。
[ec2-user@aws ~]$ awk 'BEGIN{FS=":"; OFS=">"} {print $1, $2}' file
The dog>There is a big dog and a little dog in the park
The cat>There is a big cat and a little cat in the park
The tiger>There is a big tiger and a litle tiger in the park
RS和ORS用法
# 默认情况下RS和ORS设置为“\n”
# 表示输入数据流中的每一行作为一条记录,输出时每条记录之间也以“\n”进行分割。
下面以file2文件为例,fiel2文件中内容如下:
Tom is a student
and he is 20 years old
Bob is a teacher
and he is 40 years old
# 默认情况下,每行作为一条记录处理
# 但此种情况下,要把第一行和第二行作为一条记录处理,第三行和第四行作为一条记录处理
[ec2-user@aws ~]$ awk 'BEGIN{RS=""; ORS="\n"; FS="and"; OFS=","} {print $1, $2}' file1 file2
Tom is a student
, he is 20 years old
Bob is a teacher
, he is 40 years old
ARGC和ARGV
# ARGC表示命令行中的参数个数,ARGV是参数数组
# 可见,每处理一行数据时,都是两个参数,第一个是awk本身,第二个是处理的文件名
awk -F: '{print ARGC, ARGV[0], ARGV[1]}' file
2 awk file
2 awk file
2 awk file
NR和FNR
# FNR表示处理文件的当前记录号,NR表示所有处理文件已处理的输入记录个数
[ec2-user@aws ~]$ awk -F: '{print "NR="NR, "FNR="FNR, $2}' file file1
NR=1 FNR=1 There is a big dog and a little dog in the park
NR=2 FNR=2 There is a big cat and a little cat in the park
NR=3 FNR=3 There is a big tiger and a litle tiger in the park
NR=4 FNR=1
NR=5 FNR=2
# 注意,不要对NR和FNR加$
# 例如,如果对NR加$,加入NR等于5,实际就是取每条记录的第5个数据字段,实际没有这么多,只能取到空
2、用户自定义变量
在脚本中使用用户自定义变量
建立一个script1的脚本,内容如下:
awk '
BEGIN{
FS = ":"
name = "lzj>"
}
{
$1 = name
print $0
}' file
运行该脚本 ./script
[ec2-user@aws ~]$ ./script
lzj> There is a big dog and a little dog in the park
lzj> There is a big cat and a little cat in the park
lzj> There is a big tiger and a litle tiger in the park
# 在脚本中直接定义了一个name变量,在脚本程序中可以直接引用该变量。
# 注意在yaml命令中,赋值语句“=”的前后是不能有空格的
# 但是在awk程序的内部是可以有的,因为awk是一种单独的编程语言。
在命令行中使用变量
首先定义一个script2脚本,其内容为:
BEGIN{
FS = ":"
}
{
print $n
}
脚本中有一个n的变量,在命令行中传入
[ec2-user@aws ~]$ awk -f script2 n=2 file
There is a big dog and a little dog in the park
There is a big cat and a little cat in the park
There is a big tiger and a litle tiger in the park
注意一个问题:在命令行中传入的参数,默认在BEGIN是不能获取的,例如
script2脚本改为如下,在BEGIN部分获取n的值:
BEGIN{
FS = ":"
print "请输出第二部分...", n
}
{
print $n
}