ITPub博客

首页 > 数据库 > 数据库开发技术 > 三剑客之 awk

三剑客之 awk

原创 数据库开发技术 作者:咸鱼运维杂谈 时间:2022-11-12 20:00:00 0 删除 编辑


本篇文章参考文献:

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 学习之旅吧!


01

初识 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.txt
Proto 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.txt


2、过滤条件:第三列的值大于等于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.txt
3306           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.txt
1 $ 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.txt
2 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/passwd
root 0bin 1daemon 2adm 3lp 4sync 5shutdown 6halt 7mail 8operator 11games 12ftp 14nobody 99systemd-network 192dbus 81polkitd 999sshd 74postfix 89chrony 998tss 59ntp 38tcpdump 72zabbix 997minion2 1000nginx 996


指定为 tab

awk -F ':' '{print $1,$3} ' OFS='\t' /etc/passwd
root    0bin     1daemon  2adm     3lp      4sync    5shutdown        6halt    7mail    8operator        11games   12ftp     14nobody  99systemd-network 192dbus    81polkitd 999sshd    74postfix 89chrony  998tss     59ntp     38tcpdump 72zabbix  997minion2 1000nginx   996


4、输出记录以 tab 分隔(以 /etc/passwd 为例)

记录(行)分隔符默认是换行符

awk -F ':' '{print $1,$3} '  /etc/passwd
root 0bin 1daemon 2adm 3lp 4sync 5shutdown 6halt 7mail 8operator 11games 12ftp 14nobody 99systemd-network 192dbus 81polkitd 999sshd 74postfix 89chrony 998tss 59ntp 38tcpdump 72zabbix 997minion2 1000nginx 996


指定为 tab

awk -F ':' '{print $1,$3} ' ORS="\t" /etc/passwd
root 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 996


awk 正则


字符串匹配

~ 表示模式开始、/ /中是模式。这就是一个正则表达式的匹配

1、匹配 LISTEN

awk '$6 ~ /LISTEN/ {print $0}' test.txt
tcp        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.txt
tcp        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.txt
tcp        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.txt
$ cat 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.txt
chrony, 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/passwd


4、统计有多少条 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



原文作者:咸鱼运维杂谈;如有侵权,请联系管理员删除。

上一篇: 三剑客之 sed
请登录后发表评论 登录
全部评论
最新的技术文章首先发布在微信公众号:咸鱼运维杂谈 擅长Linux系统维护、开源软件维护、自动化运维等领域,博客主要偏向于学习笔记及经历分享

注册时间:2021-05-29

  • 博文量
    193
  • 访问量
    84250