awk 命令是知名的文本处理工具,善于对文本进行复杂格式处理,与 grep、sed 并称shell中文本处理的三剑客。
awk 名称起源于其三位作者的姓 Aho、Weingberger 和 Kernighan,和 sed 类似 awk 命令也是按行读取和处理,不过是将一行分成若干个字段进行处理。
基本用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@centos uphie]# awk --help
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options: GNU long options: (standard)
-f progfile --file=progfile
-F fs --field-separator=fs
-v var=val --assign=var=val
Short options: GNU long options: (extensions)
-b --characters-as-bytes
-c --traditional
-C --copyright
-d[file] --dump-variables[=file]
-e 'program-text' --source='program-text'
-E file --exec=file
-g --gen-pot
-h --help
-L [fatal] --lint[=fatal]
-n --non-decimal-data
-N --use-lc-numeric
-O --optimize
-p[file] --profile[=file]
-P --posix
-r --re-interval
-S --sandbox
-t --lint-old
-V --version
To report bugs, see node `Bugs' in `gawk.info', which is
section `Reporting Problems and Bugs' in the printed version.
gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.
Examples:
gawk '{ sum += $1 }; END { print sum }' file
gawk -F: '{ print $1 }' /etc/passwd
awk 命令基本形式为:awk [选项] '脚本命令' 文件名
。
脚本命令形式为:
/模式
,如/ing$
/模式/动作
,如/^186/{print $0}
动作
,如{print $1}
有几点需要注意:
- awk 脚本命令需要用单引号
''
- awk 动作需要用
{}
包裹 - 模式是正则表达式或条件表达式,或两者混用
- 正则用
/
作为界定符 - 多个动作之间用
;
分隔
常用选项
-F fs
用来将 fs 作为行的分隔符,默认分隔符为空格或制表符。
如以 ,
为分隔符,获取第二个元素:
1
2
[root@centos uphie]# echo 'apple,huawei,oppo' | awk -F , '{print $2}'
huawei
指定多个分隔符,这几个分隔符之间是或的关系:
1
2
[root@centos uphie]# echo 'Bob:I love linux' | awk -F '[: ]' '{print NF " words"}'
4 words
-f file
从脚本文件中读取 awk 脚本命令。
假设有一个成绩单:
1
2
3
4
5
6
[root@centos uphie]# cat grades.csv
姓名,语文,数学,英语
悟空,70,98,23
八戒,83,79,49
悟净,56,90,89
小白龙,67,60,99
使用 awk 脚本成绩统计每个人的总分:
1
2
3
4
5
6
7
[root@centos uphie]# cat script.awk
BEGIN{FS=","} NR>1 {print $1"总分:"($2+$3+$4)}
[root@centos uphie]# awk -f script.awk grades.csv
悟空总分:191
八戒总分:211
悟净总分:235
小白龙总分:226
-v var=”value”
指定变量
换行输出:
1
2
3
4
[root@centos uphie]# echo 'apple,huawei,xiaomi' | awk -F, -v OFS="\n" '{print $1,$2,$3}'
apple
huawei
xiaomi
awk 脚本语言
awk 命令操作符
数学运算符
+
,加-
,减*
,乘\
,除%
,取余++
,自增1--
,自减1+=
,自加-=
,自减*=
,自乘/=
,自除^
,幂运算
如求平均值:
1
2
[root@centos uphie]# echo "10,12,13,14" | awk -F , '{print(($1+$2+$3+$4)/4)}'
12.25
逻辑关系符
&&
,且||
,或!
,非
假设有一个成绩单:
1
2
3
4
5
6
[root@centos uphie]# cat grades.csv
姓名,语文,数学,英语
悟空,70,98,23
八戒,83,79,49
悟净,56,90,89
小白龙,67,60,99
找出语文或英语不及格的学生成绩:
1
2
3
4
[root@centos uphie]# awk -F , 'NR>1&&($2<60||$4<60){print $0}' grades.csv
悟空,70,98,23
八戒,83,79,49
悟净,56,90,89
比较操作符
>
,大于<
,小于>=
,大于等于<=
,小于等于!=
,不等于==
,等于
awk 命令内置变量
$0
,完整行$n
,第 n 个结果,n 从1开始计,n 可以为表达式,如$(1+2)
等效于$3
NF
,字段数量NR
,行号FNR
,与NR
类似,但多文件记录不递增,每个文件都从1开始ARGC
,命令行参数个数FILENAME
,当前输入文档名称FS
,字段分隔符OFS
,输出字段分隔符,默认为空格ORS
,输出记录分隔符,默认为换行符\n
RS
,输入记录分隔符,默认为换行符\n
如,将两个文件连带行号合并输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@centos uphie]# cat fruit.txt
banana
watermelon
grape
peach
[root@centos uphie]# cat animal.txt
lion
cat
wolf
bear
duck
[root@centos uphie]# awk '{print NR,$0}' fruit.txt animal.txt
1 banana
2 watermelon
3 grape
4 peach
5 lion
6 cat
7 wolf
8 bear
9 duck
awk 命令常用内置函数
length
计算字符数量
1
2
[root@centos uphie]# echo apple | awk '{print length($0)}'
5
substr
形式 substr(raw_str,start,cnt)
从第3个字符开始截取,直接结束:
1
2
[root@centos uphie]# echo 小明,1902343,M | awk -F, '{print substr($2,3)}'
02343
截取从第3个字符开始的3个字符
1
2
[root@centos uphie]# echo 小明,1902343,M | awk -F, '{print substr($2,3,3)}'
023
rand
产生 (0,1) 区间内的随机数
产生10个100以内的随机数:
1
2
3
4
5
6
7
8
9
10
11
[root@centos uphie]# awk 'BEGIN{for(i=1;i<=10;i++)print int(100*rand())}'
24
29
85
15
59
19
81
17
48
15
system
可以用来执行系统命令
如执行 ping 命令:
1
2
3
4
5
6
7
8
9
10
11
[root@centos uphie]# echo baidu.com | awk '{system("ping -c 5 " $0)}'
PING baidu.com (110.242.68.66) 56(84) bytes of data.
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=1 ttl=128 time=44.5 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=2 ttl=128 time=44.3 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=3 ttl=128 time=43.9 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=4 ttl=128 time=43.1 ms
64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=5 ttl=128 time=43.9 ms
--- baidu.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 43.153/44.000/44.538/0.547 ms
自定义函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@centos uphie]# cat randletter.awk
BEGIN{
CNT=10
for(i=1;i<=CNT;i++){
print randletter()
}
}
# 自定义函数,返回小于等于 n 的随机整数
function randint(n){
return int(n*rand())+1
}
# 自定义函数,返回 [a-zA-Z0-9] 的随机字母
function randletter(){
return substr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",randint(62),1)
}
生成随机字符:
1
2
3
4
5
6
7
8
9
10
11
[root@centos uphie]# awk -f randletter.awk
o
s
0
j
K
l
Y
k
E
j
条件分支语句
单分支:
找到语文及格的人和成绩:
1
2
3
4
[root@centos uphie]# awk -F , '{if(NR>1&&$2>60)print $1"语文:"$2}' grades.csv
悟空语文:70
八戒语文:83
小白龙语文:67
多分支:
给每个人语文成绩评级:
1
2
3
4
[root@centos uphie]# awk -F , 'NR>1 {if($2>90)print $1"语文成绩很优秀:"$2;else if(NR>1&&$2>70&&$2<90) print $1"成绩良好:"$2;else print $1"成绩欠佳:"$2}' grades.csv悟空成绩欠佳:70
八戒成绩良好:83
悟净成绩欠佳:56
小白龙成绩欠佳:67
循环语句
有这样一个文件,里面存储了一堆数据,每行中数据用空格分隔
1
2
3
4
5
[root@centos uphie]# cat data.txt
10 78 93
94 67 -4
7 9 20
12 7 8
统计 netstat -anp
状态为 LISTEN
和 CONNECT
的连接数量分别是多少:
1
2
3
[root@centos uphie]# netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'
LISTEN 7
CONNECTED 104