AWK是一个优良的文本工具,是Linux环境下现有的功能最强大的数据处理引擎之一。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。他的创建者创建者已将它正式定义为“样式扫描和处理语言”。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
不管语法怎么复杂,其语法始终为:
awk 'pattern {action}'
pattern是执行条件,通常是正则表达式
条件类型 | 条件 | 条件说明 |
---|---|---|
AWK保留字 | BEGIN | 在AWK程序开始时执行,仅会在程序开始的时候被执行一次 |
AWK保留字 | END | 在AWK程序结束之前执行,仅会在程序结束的时候执行一次 |
关系运算符 | > | 大于 |
关系运算符 | < | 小于 |
关系运算符 | == | 判断是否等于 |
关系运算符 | >= | 大于等于 |
关系运算符 | <= | 小于等于 |
关系运算符 | != | 不等于 |
关系运算符 | pattern1~pattern2 | 判断pattern1是否包含能匹配上pattern2的字符串 |
关系运算符 | pattern1!~pattern2 | 判断pattern1是否不包含能匹配上pattern2的字符串 |
正则判断 | /pattern/ | //之间为正则表达式,也支持字符串 |
awk的动作通常为:格式化输出
$n:表示第几个变量,如:$1,$2,就表示第一个变量,第二个变量
$0:表示执行过程中当前行的全部内容,即,所有的变量值
$NF:表示最后一个变量
NR:表示记录数,即当前执行的行号
FNR:同NR,这个是相对于文件而言的
NF:表示字段个数
FS:字段分隔符,默认是任何的空格
RS:记录分隔符,默认是一个换行符
OFS:输出字段分隔符,默认是一个空格
ORS:输出记录分隔符,默认是换行符
ARGC:命令行参数的数量
ARGV:命令行参数的数组
ARGIND:命令行当前文件的位置(从0开始)
CONVFMT:数字转换格式(默认为:%.6g)
OFMT:数字的输出格式(默认是:%.6g)
ENVIRON:环境变量关联数组
ERRNO:最后一个系统错误描述
FIELDWIDTHS:字段宽度列表(空格分隔)
FILENAME:当前输入的文件的名字
IGNORECASE:如果为真,就忽略大小写
RSTART:match函数匹配的字符串的第一个位置
RLENGTH:match函数匹配的字符串的长度
SUBSEP:数组下标分隔符(默认是34)
现在,先准备一个测试文件test.txt,文件内容如下:
//假设该文件保存的数据格式为
//名字 语文成绩 数学成绩 英语成绩 物理成绩 化学成绩
xiaoming 98 99 44 22 56
xiaohong 56 78 24 55 99
xiaodong 77 50 29 64 72
格式化输出:输出每个人对应的数学成绩,即,输出第一个和第三个字段
awk '{printf $1 "\t" $3 "\n"}' test.txt
#此处可以使用print代替printf,使用printf时,需要在后面加上\n,否则的话不会换行
#print会在输出后自动换行,所以不需要加。
#输出多个字符用空格隔开
#执行结果如下
root@localhost:/home/test/mi> awk '{printf $1 "\t" $3 "\n"}' test.txt
xiaoming 99
xiaohong 78
xiaodong 50
格式化输出:在上面的案例的输出结果之前,输出“This is math.”
awk 'BEGIN {print 'This is math.'} {printf $1 "\t" $3 "\n"}' test.txt
#执行结果如下
root@localhost:/home/test/mi> awk 'BEGIN {print 'This is math.'} {printf $1 "\t" $3 "\n"}' test.txt
This is math.
xiaoming 99
xiaohong 78
xiaodong 50
关系运算符的使用:查询数学成绩大于90的人
cat test.txt | grep -v name |awk '$3 > 90 {print $1}'
#判断$3>90成立后,才会执行后续的输出操作
#运行结果如下:
root@localhost:/home/test/mi> cat test.txt | grep -v name |awk '$3 > 90 {print $1}'
xiaoming
正则匹配:查找xiaodong的所有成绩
awk '/xiaodong/ {print}' test.txt
#//中表示要匹配的正则表达式
#运行结果如下:
root@localhost:/home/test/mi> awk '/xiaodong/ {print}' test.txt
xiaodong 77 50 29 64 72
操作字符串:输出a_nb_cidskf_frk_fds最后一个_后面的字符串
root@localhost:/home/test/mi> echo a_nb_cidskf_frk_fds | awk -F '_' '{print $NF}'
fds
next语句
在逐行匹配的过程中,遇到next关键字,会跳过这一行,直接读取下一行
getline
输出重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1
具体用法:
for循环
for(变量 in 数组)
{代码块}
for(变量;条件;表达式)
{代码块}
while循环
while(表达式)
{代码块}
do … while循环
do(代码块)
while(表达式)
关键字
break:退出循环
continue:退出本次循环,进入下一次循环
next:读取下一行
exit:退出循环进入end语句,如果没有end语句,就直接退出
awk的数组不用提前声明,也不用指定大小。数组的初始化用0或者空字符串来实现。具体的使用通过上下文来定。
数组的定义
awk 'BEGIN{
Array[1]="xiao"
Array[2]="mi"
Array["birth"]="1994"
Array["hobby"]="music"
}'
输出数组的内容
#有输出(默认无序)
for(item in Array)
{print Array[item]};
#乱序输出
#此处需要注意的是下标是从1开始
for(i=1;i<length(Array);i++)
{print Array[1]}
输出数组的长度
awk 'BEGIN{
str="this is test data for xiaomi
//通过split获取数组长度
lens=split(str,Array,"")
//通过length获取数组的长度
//需要注意的是,如果AWK的版本过低,是不支持length获取数组长度的
print length(Array),lens
}'
判断数组中是否存在某一指定的值
错误的做法
首先要注意的是,一旦出现数组的引用,AWK就会自动创建该元素,这是本次演示的错误原因
awk 'BEGIN{
Array[1]="xiao"
Array[2]="mi"
Array["birth"]="1994"
Array["hobby"]="music"
//此处,会自动创建一个Array["home"]的引用,其值为空
if(Array["home"]!="China"){
print "not found home"
};
for(item in Array){
print item,Array[item];
}
}'
//此时的运行结果是:
not found home
birth 1994
hobby music
home
1 xiao
2 mi
//可以发现此时虽然得到我们想要的结果了,但是数组本身发生了变化,多了一个元素
正确的做法
awk 'BEGIN{
Array[1]="xiao"
Array[2]="mi"
Array["birth"]="1994"
Array["hobby"]="music"
if("home" in Array){
print "There is home"
};
for(item in Array){
print item,Array[item];
}
}'
//此时的运行结果是
birth 1994
hobby music
1 xiao
2 mi
删除数组的某一元素
#会删除Array["hobby"]的元素值
delete Array["hobby"]