本篇文章参考文献:
The GNU Awk User’s Guide
https://www.gnu.org/software/gawk/manual/gawk.html
awk 是贝尔实验室1977年搞出来的文本打印神器
之所以叫 awk 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和
Brian Kernighan 的 Family Name 的首字符
平常在工作当中也会经常用到 awk,如果稍微掌握一点点用法,能够极大地提高工作效率
今天这篇文章主要目的还是为了引起大家对 awk 的兴趣,对于这个上古神器还需要大家自行去查阅相关文档去进一步学习
废话少说,开始今天的 awk 学习之旅吧!
通常,awk 是以文件的一行为处理单位的,awk 每接受文件的一行,就会执行相应的命令来处理文本
例如:执行 awk 时,它依次对 /etc/passwd 中的每一行执行 print 命令
awk '{print 1 $0}' /etc/passwd
过滤
从 netstat 命令中提取了以下信息作为例子

test.txt
Proto Recv-Q Send-Q Local-Address Foreign-Address Statetcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTENtcp 0 0 0.0.0.0:80 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTENtcp 0 0 saltedfish.cn:80 124.205.5.146:18245 TIME_WAITtcp 0 0 saltedfish.cn:80 61.140.101.185:37538 FIN_WAIT2tcp 0 0 saltedfish.cn:80 110.194.134.189:1032 ESTABLISHEDtcp 0 0 saltedfish.cn:80 123.169.124.111:49809 ESTABLISHEDtcp 0 0 saltedfish.cn:80 116.234.127.77:11502 FIN_WAIT2tcp 0 0 saltedfish.cn:80 123.169.124.111:49829 ESTABLISHEDtcp 0 0 saltedfish.cn:80 183.60.215.36:36970 TIME_WAITtcp 0 4166 saltedfish.cn:80 61.148.242.38:30901 ESTABLISHEDtcp 0 1 saltedfish.cn:80 124.152.181.209:26825 FIN_WAIT1tcp 0 0 saltedfish.cn:80 110.194.134.189:4796 ESTABLISHEDtcp 0 0 saltedfish.cn:80 183.60.212.163:51082 TIME_WAITtcp 0 1 saltedfish.cn:80 208.115.113.92:50601 LAST_ACKtcp 0 0 saltedfish.cn:80 123.169.124.111:49840 ESTABLISHEDtcp 0 0 saltedfish.cn:80 117.136.20.85:50025 FIN_WAIT2tcp 0 0 :::22 :::* LISTEN
比如说我们想输出例子中的第一列和第四列
$n:表示第几列($0表示整个内容)
执行的操作只能是单引号
awk '{print $1, $4}' test.txtProto Local-Addresstcp 0.0.0.0:3306tcp 0.0.0.0:80tcp 127.0.0.1:9000tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp saltedfish.cn:80tcp :::22
加上过滤条件
1、过滤条件:第一列的值为 tcp && 第六列的值为 LISTEN
awk '$1=="tcp" && $6=="LISTEN"' test.txt2、过滤条件:第三列的值大于等于1,打印过滤出的内容
awk '$3>=1 {print$0}' test.txt常用的比较运算符
==:等于!=:不等于:大于<:=:<=:
指定分隔符
默认是以空格作为分隔符
-F 参数:指分隔符
1、以空格作为分隔符,打印出第四列内容
awk '{print $4}' test.txt或者awk -F ' ' '{print $4}' test.txt
Local-Address0.0.0.0:33060.0.0.0:80127.0.0.1:9000saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80saltedfish.cn:80:::22
2、以 “:” 作为分隔符,打印出第二列内容
awk -F ':' '{print $2}' test.txt3306 0.0.0.080 0.0.0.09000 0.0.0.080 124.205.5.14680 61.140.101.18580 110.194.134.18980 123.169.124.11180 116.234.127.7780 123.169.124.11180 183.60.215.3680 61.148.242.3880 124.152.181.20980 110.194.134.18980 183.60.212.16380 208.115.113.9280 123.169.124.11180 117.136.20.85
3、如果要指定多个分隔符,可以这样:
awk -F '[;:]'
awk 内置变量

1、我们对输出结果加上行号(过滤条件:第三列的值大于1)
awk '$3>=1 {print NR,$0}' test.txt1 $ cat netstat.txt2 Proto Recv-Q Send-Q Local-Address Foreign-Address State13 tcp 0 4166 saltedfish.cn:80 61.148.242.38:30901 ESTABLISHED14 tcp 0 1 saltedfish.cn:80 124.152.181.209:26825 FIN_WAIT117 tcp 0 1 saltedfish.cn:80 208.115.113.92:50601 LAST_ACK
2、忽略第一行(即 NR>1)
awk '$3>=1 && NR>1 {print NR,$0}' test.txt2 Proto Recv-Q Send-Q Local-Address Foreign-Address State13 tcp 0 4166 saltedfish.cn:80 61.148.242.38:30901 ESTABLISHED14 tcp 0 1 saltedfish.cn:80 124.152.181.209:26825 FIN_WAIT117 tcp 0 1 saltedfish.cn:80 208.115.113.92:50601 LAST_ACK
3、输出字段以 tab 分隔(以 /etc/passwd 为例)
字段分隔符默认是空格
awk -F ':' '{print $1,$3} ' /etc/passwdroot 0bin 1daemon 2adm 3lp 4sync 5shutdown 6halt 7mail 8operator 11games 12ftp 14nobody 99192dbus 81polkitd 999sshd 74postfix 89chrony 998tss 59ntp 38tcpdump 72zabbix 997minion2 1000nginx 996
指定为 tab
awk -F ':' '{print $1,$3} ' OFS='\t' /etc/passwdroot 0bin 1daemon 2adm 3lp 4sync 5shutdown 6halt 7mail 8operator 11games 12ftp 14nobody 99192dbus 81polkitd 999sshd 74postfix 89chrony 998tss 59ntp 38tcpdump 72zabbix 997minion2 1000nginx 996
4、输出记录以 tab 分隔(以 /etc/passwd 为例)
记录(行)分隔符默认是换行符
awk -F ':' '{print $1,$3} ' /etc/passwdroot 0bin 1daemon 2adm 3lp 4sync 5shutdown 6halt 7mail 8operator 11games 12ftp 14nobody 99192dbus 81polkitd 999sshd 74postfix 89chrony 998tss 59ntp 38tcpdump 72zabbix 997minion2 1000nginx 996
指定为 tab
awk -F ':' '{print $1,$3} ' ORS="\t" /etc/passwdroot 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 operator 11 games 12 ftp 14 nobody 99 systemd-network 192 dbus 81 polkitd 999 sshd 74 postfix 89 chrony 998 tss 59 ntp 38 tcpdump 72 zabbix 997 minion2 1000 nginx 996awk 正则

字符串匹配
~ 表示模式开始、/ /中是模式。这就是一个正则表达式的匹配
1、匹配 LISTEN
awk '$6 ~ /LISTEN/ {print $0}' test.txttcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTENtcp 0 0 0.0.0.0:80 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTENtcp 0 0 :::22 :::* LISTEN
2、支持模糊匹配
匹配 LIS 的话,LISTEN 和 EATABLISTED 都会输出
awk '$6 ~ /LIS/ {print $0}' test.txttcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTENtcp 0 0 0.0.0.0:80 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTENtcp 0 0 saltedfish.cn:80 110.194.134.189:1032 ESTABLISHEDtcp 0 0 saltedfish.cn:80 123.169.124.111:49809 ESTABLISHEDtcp 0 0 saltedfish.cn:80 123.169.124.111:49829 ESTABLISHEDtcp 0 4166 saltedfish.cn:80 61.148.242.38:30901 ESTABLISHEDtcp 0 0 saltedfish.cn:80 110.194.134.189:4796 ESTABLISHEDtcp 0 0 saltedfish.cn:80 123.169.124.111:49840 ESTABLISHEDtcp 0 0 :::22 :::* LISTEN
3、多个匹配条件
awk '$6 ~ /LISTEN|FIN/{print $0}' test.txttcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTENtcp 0 0 0.0.0.0:80 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTENtcp 0 0 saltedfish.cn:80 61.140.101.185:37538 FIN_WAIT2tcp 0 0 saltedfish.cn:80 116.234.127.77:11502 FIN_WAIT2tcp 0 1 saltedfish.cn:80 124.152.181.209:26825 FIN_WAIT1tcp 0 0 saltedfish.cn:80 117.136.20.85:50025 FIN_WAIT2tcp 0 0 :::22 :::* LISTEN
4、取反匹配
awk '$6 !~ /LISTEN|FIN/ {print $0}' test.txtcat netstat.txtProto Recv-Q Send-Q Local-Address Foreign-Address Statetcp 0 0 saltedfish.cn:80 124.205.5.146:18245 TIME_WAITtcp 0 0 saltedfish.cn:80 110.194.134.189:1032 ESTABLISHEDtcp 0 0 saltedfish.cn:80 123.169.124.111:49809 ESTABLISHEDtcp 0 0 saltedfish.cn:80 123.169.124.111:49829 ESTABLISHEDtcp 0 0 saltedfish.cn:80 183.60.215.36:36970 TIME_WAITtcp 0 4166 saltedfish.cn:80 61.148.242.38:30901 ESTABLISHEDtcp 0 0 saltedfish.cn:80 110.194.134.189:4796 ESTABLISHEDtcp 0 0 saltedfish.cn:80 183.60.212.163:51082 TIME_WAITtcp 0 1 saltedfish.cn:80 208.115.113.92:50601 LAST_ACKtcp 0 0 saltedfish.cn:80 123.169.124.111:49840 ESTABLISHED
BEGIN & END
BEGIN 和 END 这两个关键字意味着执行前和执行后的意思,语法如下:
BEGIN{ 这里面放的是执行前的语句 }
END {这里面放的是处理完所有的行后要执行的语句 }
{这里面放的是处理每一行时要执行的语句}
以下面内容为例(将 top 输出结果重定向到 top.txt 中)
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDroot 1 0.0 0.1 125636 4148 ? Ss 11月11 0:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 22root 2 0.0 0.0 0 0 ? S 11月11 0:00 [kthreadd]root 4 0.0 0.0 0 0 ? S< 11月11 0:00 [kworker/0:0H]root 6 0.0 0.0 0 0 ? S 11月11 0:00 [ksoftirqd/0]root 7 0.0 0.0 0 0 ? S 11月11 0:00 [migration/0]root 8 0.0 0.0 0 0 ? S 11月11 0:00 [rcu_bh]root 9 0.0 0.0 0 0 ? R 11月11 0:07 [rcu_sched]root 10 0.0 0.0 0 0 ? S< 11月11 0:00 [lru-add-drain]root 11 0.0 0.0 0 0 ? S 11月11 0:00 [watchdog/0]root 12 0.0 0.0 0 0 ? S 11月11 0:00 [watchdog/1]root 13 0.0 0.0 0 0 ? S 11月11 0:00 [migration/1]root 14 0.0 0.0 0 0 ? S 11月11 0:00 [ksoftirqd/1]root 16 0.0 0.0 0 0 ? S< 11月11 0:00 [kworker/1:0H]root 18 0.0 0.0 0 0 ? S 11月11 0:00 [kdevtmpfs]root 19 0.0 0.0 0 0 ? S< 11月11 0:00 [netns]root 20 0.0 0.0 0 0 ? S 11月11 0:00 [khungtaskd]root 21 0.0 0.0 0 0 ? S< 11月11 0:00 [writeback]root 22 0.0 0.0 0 0 ? S< 11月11 0:00 [kintegrityd]root 23 0.0 0.0 0 0 ? S< 11月11 0:00 [bioset]root 24 0.0 0.0 0 0 ? S< 11月11 0:00 [bioset]root 25 0.0 0.0 0 0 ? S< 11月11 0:00 [bioset]root 26 0.0 0.0 0 0 ? S< 11月11 0:00 [kblockd]root 27 0.0 0.0 0 0 ? S< 11月11 0:00 [md]root 28 0.0 0.0 0 0 ? S< 11月11 0:00 [edac-poller]root 29 0.0 0.0 0 0 ? S< 11月11 0:00 [watchdogd]root 35 0.0 0.0 0 0 ? S 11月11 0:00 [kswapd0]root 36 0.0 0.0 0 0 ? SN 11月11 0:00 [ksmd]root 37 0.0 0.0 0 0 ? SN 11月11 0:00 [khugepaged]root 38 0.0 0.0 0 0 ? S< 11月11 0:00 [crypto]root 46 0.0 0.0 0 0 ? S< 11月11 0:00 [kthrotld]root 49 0.0 0.0 0 0 ? S< 11月11 0:00 [kmpath_rdacd]root 50 0.0 0.0 0 0 ? S< 11月11 0:00 [kaluad]root 51 0.0 0.0 0 0 ? S< 11月11 0:00 [kpsmoused]root 53 0.0 0.0 0 0 ? S< 11月11 0:00 [ipv6_addrconf]root 66 0.0 0.0 0 0 ? S< 11月11 0:00 [deferwq]root 104 0.0 0.0 0 0 ? S 11月11 0:00 [kauditd]root 283 0.0 0.0 0 0 ? S< 11月11 0:00 [mpt_poll_0]
1、计算每个用户的进程占了多少内存
awk 'NR!=1{a[$1]+=$6;} END { for(i in a) print i ", " a[i]"KB";}' top.txtchrony, 1860KBnginx, 3688KBdbus, 2492KBpolkitd, 14152KBroot, 208636KB
2、统计当前目录下文件所占空间大小
ll -h | awk 'BEGIN {size=0} {size=size+$5} END{print size "KB"}'
3、统计 /etc/passwd 中用户数量
awk '{count++} END{print count}' /etc/passwd4、统计有多少条 tcp 连接
(减掉 2 是因为前面两条字段不是 tcp 连接)
netstat -tnlp | awk '{count++} END{print count-2}'

5、打印出 11日到12日 13点到14点之间的日志信息

awk '{if ($2>10 && $2<12 && $3>"13:00:00" && $3<"14:00:00") print}' /var/log/messages
原文作者:咸鱼运维杂谈;如有侵权,请联系管理员删除。