awk命令用法

作为Linux命令三剑客之一的awk功能非常强大,用法也较为复杂,最擅长是按列提取值,awk结合grep结合xargs可以完成非常多的事,网上教程很多,我就以解析一个csv文件为例演示awk最实用的一些功能。

test.csv内容

姓名 成绩
张三 95
李四
王五 98
平均分 96.5

文本内容

1
2
3
4
5
姓名,成绩
张三,95
李四,
王五,98
平均分,96.5

需求

打印除了表头(第一行)和汇总(最后一行)外所有行的第一列和最后一列,但如果最后一列是空的则这行不打印。
对于上例,打印出来应该是

1
2
张三 95
王五 98

处理语句

1
cat test.csv|awk 'NR>1'|awk 'NR!=1 {print prev} {prev=$0}'|awk -F, '$NF ~ /[^\t\r\n ]/ {print $1,$NF}'

其中用到了3次awk:
第一个awk,awk 'NR>1',实现去掉首行
第二个awk,awk 'NR!=1 {print prev} {prev=$0}',实现去掉最后一行
第三个awk,awk -F, '$NF ~ /[^\t\r\n ]/ {print $1,$NF}',指定了,为分隔符,当最后一列不空时打印第一列和最后一列

awk命令格式

awk

options

最长用的就是 -F 用来指定列分割符

pattern & action

类似if条件,可以用()括起来也可以不括,多个条件&&连接,多个条件||连接,只有满足条件才会做后面的动作,省略pattern相当于条件为真,即对每一行做action动作。action可以和{}一起省略,省略时执行默认的action输出整行。action可以是多条语句,语句间用;分割。
pattern {action}整体可以重复多次,表示多一行执行多组pattern {action}

在pattern和action中可以使用的特殊符号:

行号:NR
列数:NF
NF是一个数字,而$NF是最后一列的值。

file

即需要处理文件的文件名,通常使用awk处理来自管道的文本,所以file通常是省略的。

一个实用的例子

获取各个网口配置的IPv4

1
ifconfig|awk 'prev ~ /.+:/ && $1=="inet" {print prev,$2} {prev=$1}'

ifconfig的输出类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
inet 192.168.1.242 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::20c:29ff:fe7d:e0 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:7d:00:e0 txqueuelen 1000 (Ethernet)
RX packets 523230074 bytes 791300064486 (791.3 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 17037016 bytes 1268820578 (1.2 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 138 bytes 13090 (13.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 138 bytes 13090 (13.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

处理后的输出为

1
2
ens33: 192.168.1.242
lo: 127.0.0.1