首页 Linux awk 命令
文章
取消

Linux awk 命令

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 状态为 LISTENCONNECT 的连接数量分别是多少:

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
本文由作者按照 CC BY 4.0 进行授权