awk是一种样式扫描与处理工具。但其功能却大大强于sed和grep。awk提供了极其强大的功能,它几乎可以完成grep和sed所能完成的全部工作,
同时,它还可以可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。
它具备了一个完整的语言所应具有的几乎所有精美特性。实际上,awk的确拥有自己的语言:样式扫描和处理语言。
它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
基本用法
从netstat -tnlp > netstat.txt
命令中提取了如下信息作为用例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8778 0.0.0.0:* LISTEN 2689/python
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 2265/mysqld
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN 18777/smbd
tcp 0 0 127.0.0.1:35437 0.0.0.0:* LISTEN 23842/python2
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1916/nginx: master
tcp 0 0 0.0.0.0:4369 0.0.0.0:* LISTEN 1704/epmd
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 973/sshd
tcp 0 0 127.0.0.1:58205 0.0.0.0:* LISTEN 23681/python2
tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN 18777/smbd
tcp 0 0 0.0.0.0:33443 0.0.0.0:* LISTEN 13976/phantomjs
tcp 0 0 0.0.0.0:8008 0.0.0.0:* LISTEN 2548/unicorn_rails
tcp 0 0 192.168.217.161:5673 0.0.0.0:* LISTEN 951/beam.smp
tcp 0 0 0.0.0.0:25673 0.0.0.0:* LISTEN 951/beam.smp
tcp6 0 0 :::139 :::* LISTEN 18777/smbd
tcp6 0 0 :::4369 :::* LISTEN 1704/epmd
tcp6 0 0 :::22 :::* LISTEN 973/sshd
tcp6 0 0 :::3128 :::* LISTEN 2268/(squid-1)
tcp6 0 0 :::1017 :::* LISTEN 988/xnServer
tcp6 0 0 :::443 :::* LISTEN 950/httpd
tcp6 0 0 :::445 :::* LISTEN 18777/smbd
下面是最简单最常用的awk示例,比如要想输出第1列和第4列:1
$ awk '{print $1, $4}' netstat.txt
我们再来看看awk的格式化输出,和C语言的printf没什么两样:1
2
3
4
5
6
7
8
9$ awk '{printf "%-6s %-6s %-6s %-22s %-16s %-12s\n",$1,$2,$3,$4,$5,$6}' netstat.txt
Proto Recv-Q Send-Q Local Address Foreign
tcp 0 0 0.0.0.0:8778 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:35437 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:4369 0.0.0.0:* LISTEN
...
内置变量
awk经常会使用到一些内置变量,下面是它们的含义:
内置变量 | 含义 |
---|---|
$0 | 当前记录(这个变量中存放着整个行的内容) |
$1~$n | 当前记录的第n个字段,字段间由FS分隔 |
FS | 输入字段分隔符,默认是空格或Tab |
NF | 当前记录中的字段个数,就是有多少列 |
NR | 已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中 |
FNR | 当前记录数,与NR不同的是,这个值会是各个文件自己的行号 |
RS | 输入的记录分隔符,默认为换行符 |
OFS | 输出字段分隔符,默认也是空格 |
ORS | 输出的记录分隔符,默认为换行符 |
FILENAME | 当前输入文件的名字 |
过滤记录
如何过滤记录(下面过滤条件为:第三列的值为0 && 第7列包含字符串’python’)
1 | $ awk '$3==0 && $7 ~ /python/' netstat.txt |
其中的“==”为比较运算符,其他比较运算符:!=, >, <, >=, <=
还有”~“表示正则匹配,这个就相当强大了。
如果我们需要表头的话,我们可以引入内建变量NR:1
2
3
4
5
6
7
8
9
10
11$ awk '$3==0 && $6=="LISTEN" || NR==1 ' netstat.txt
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8778 0.0.0.0:* LISTEN 2689/python
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 2265/mysqld
tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN 18777/smbd
tcp 0 0 127.0.0.1:35437 0.0.0.0:* LISTEN 23842/python2
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1916/nginx: master
tcp 0 0 0.0.0.0:4369 0.0.0.0:* LISTEN 1704/epmd
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 973/sshd
tcp 0 0 127.0.0.1:58205 0.0.0.0:* LISTEN 23681/python2
...
再加上格式化输出:1
2
3
4
5
6
7
8
9
10$ awk '$3==0 && $6=="LISTEN" || NR==1 {printf "%-20s %-20s %s\n",$4,$5,$6}' netstat.txt
Local Address Foreign
0.0.0.0:8778 0.0.0.0:* LISTEN
0.0.0.0:3306 0.0.0.0:* LISTEN
0.0.0.0:139 0.0.0.0:* LISTEN
127.0.0.1:35437 0.0.0.0:* LISTEN
0.0.0.0:80 0.0.0.0:* LISTEN
0.0.0.0:4369 0.0.0.0:* LISTEN
0.0.0.0:22 0.0.0.0:* LISTEN
...
指定分隔符
1 | $ awk 'BEGIN{FS=":"} {print $1,$3,$6}' /etc/passwd |
上面的命令也等价于:(-F的意思就是指定分隔符)1
$ awk -F: '{print $1,$3,$6}' /etc/passwd
注:如果你要指定多个分隔符,你可以这样来:1
awk -F '[;:]'
再来看一个以\t作为分隔符输出的例子(下面使用了/etc/passwd文件,这个文件是以:分隔的):1
2
3
4
5
6
7$ awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd
root 0 /root
bin 1 /bin
daemon 2 /sbin
adm 3 /var/adm
lp 4 /var/spool/lpd
sync 5 /sbin
字符串匹配
1 | $ awk '$7 ~ /python/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt |
上面示例第7列匹配”python“字符串,其实 ~ 表示模式开始。/ /中是模式,这就是一个正则表达式的匹配。
其实awk可以像grep一样的去匹配一整行,就像这样:1
2
3
4$ awk '/python/' netstat.txt
tcp 0 0 0.0.0.0:8778 0.0.0.0:* LISTEN 2689/python
tcp 0 0 127.0.0.1:35437 0.0.0.0:* LISTEN 23842/python2
tcp 0 0 127.0.0.1:58205 0.0.0.0:* LISTEN 23681/python2
再来看看模式取反的例子:1
awk '!/python/' netstat.txt
统计
下面的命令计算所有的.py文件和.txt文件大小总和:1
2$ ls -l *.py *.txt | awk '{sum+=$5} END {print sum}'
3369