AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一,可以进行正则表达式的匹配,样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数

1.基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
awk 'BEGIN{} {} END{}' file
# awk 由三部分组成,包括输入前、输入中、输入后,分别来处理数据
awk ‘BEGIN {print “Hello, world”}’ file
# BEGIN模式用于指定的第一个输入行读入之前要执行的操作,并不会对输入行进行操作
awk ‘END {print “Hello, world”}' file
# END模式用于的最后一个输入行读入之前要执行的操作,并不会对输入行进行操作
awk -f script file
# -f 指定awk脚本文件
awk -F':' '{print $1}' file
# -F 指定分割符,若没指定,默认为空格
awk ‘{print $1}’ file
# $1 打印文件全部的第一个字段
awk ‘/re/’ file
# 打印匹配到re的每一行
awk '{printf("%d\t%s\n",$5,$9)}' file
# 格式化输出

2.匹配模式

1
2
3
4
5
awk ‘/^$/ {print “This is a blank line”}’ file
# 匹配文件中的空行,打印“This is a blank line”
awk ‘$5~/^MA/’ {print “This a MA”}' file
# 正则匹配$5字段

3.操作符

算数操作符:

1
2
3
4
5
6
+ 加
- 减
* 乘
/ 除
% 取模
^ 去幂

布尔操作符:

1
2
3
|| 逻辑或
&& 逻辑与
! 逻辑非

4.正则字符

元字符:

1
2
3
4
5
6
7
8
. 匹配除换行以外的任意单个字符
* 匹配任意个(包括0个)在他前面的字符
[0-9] 匹配数字0-9,如果方括号内第一个为^表示否定匹配,匹配方括号中任意一个元素
[a-z] 匹配字母a-z,如果方括号内第一个为^表示否定匹配,匹配方括号中任意一个元素
^ 匹配开头
$ 匹配结尾
\ 转义特殊字符和元字符
\{2,4\} 匹配2-4个他前面的字符

特殊字符:

1
2
3
4
5
6
+ 匹配前面的正则表达式一次或多次出现
? 零次或者一次
| 或前后满足其一
() 正则分组
(?<=) 非获取匹配,逆向取
(?=) 非获取匹配,正向取

POSIX字符类:

1
2
3
4
5
6
7
[:alnum:] 可打印字符
[:alpha:] 字母字符
[:blank:] 空格和制表符
[:digit:] 数字字符
[:lower:] 小写字符
[:punct:] 标点符号字符
[:upper:] 大写字符

5.拓展用法

传递参数:

1
2
awk ‘$NF~search{print $0}’ search=name file
将shell中name参数传入awk中

条件表达式:

1
if(expression){action1;action2};esle if action; else action

循环:

1
2
3
4
5
6
7
8
9
10
11
# while 循环
BEGIN{i=1;while(i<=4){action1;action2}}
# do while循环:
BEGIN{do {i++;print i}while(i<4)}
# for循环:
for(i=1;i<NF;i++) action
# break 退出整个循环体
# continue 跳过后面的步骤,再一次循环

next:下一行的操作

1
2
3
4
if(expression)next; action
awk 'FILENAME=="file1"{a++;next}{print $0}'END'{print a}' file1 file2
统计file1的行数,打印file2

数组

1
2
3
4
5
6
7
8
9
10
11
12
# 定义
array[NR]=$2 存入每行的$2字段的值
# 遍历
for(x=1;x<=NR;x++)action1
# 查询
item in array
如果array[item]存在就返回1,否则就返回0
# 删除
delete array[]

关联数组

1
2
3
4
5
6
7
8
# 定义
array[$1]+=$2$1相同,则累加$2
# 遍历
for(i in array) print i,a[i]
# 例子
$ awk -F'\t' '{a[$12]+=$23} END{for (i in a)print a[i],i}'

函数

1
2
3
4
5
6
7
8
9
10
11
split($1,fullname," ")
用split创建分割数组,$1表示需要分割的字段,fullname表示数组名字," "表示用什么作为分隔符
rand()
返回随机数 0=<r<1
gsub(r,s,t)
t字符串中r正则匹配用字符串s替换 全局的sub(r,s,t)替换首个出现的
length(s)
返回字符串长度

6.使用例子

有一份学生成绩表,根据学生成绩表,打印学生姓名,平均分,等级
A 100~90
B 89~80
C 79~70
D 69~0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cat grades
mona 70 77 85 83 70 89
john 85 92 78 94 88 91
andrea 89 92 78 94 88 91
jasper 84 88 80 92 84 82
dunce 64 80 60 60 61 62
ellis 90 98 89 96 96 92
$ awk '{total=0;for(i=2;i<=NF;i++) total+=$i;avg=total/(NF-1);if(avg>=90) grade="A";else if(avg>=80) grade ="B";else if(avg>=70)grade="C";else if(avg>=60)grade="D";else grade="F";++a[grade];print $1,avg,grade}' grades
mona 79 C
john 88 B
andrea 90.5 A
jasper 85 B
dunce 64.5 D
ellis 93.5 A