你的位置:首页 > 操作系统

[操作系统]awk(1)


从netstat命令中提取了如下信息作为用例

$ cat netstat.txtProto 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 coolshell.cn:80    124.205.5.146:18245     TIME_WAITtcp    0   0 coolshell.cn:80    61.140.101.185:37538    FIN_WAIT2tcp    0   0 coolshell.cn:80    110.194.134.189:1032    ESTABLISHEDtcp    0   0 coolshell.cn:80    123.169.124.111:49809    ESTABLISHEDtcp    0   0 coolshell.cn:80    116.234.127.77:11502    FIN_WAIT2tcp    0   0 coolshell.cn:80    123.169.124.111:49829    ESTABLISHEDtcp    0   0 coolshell.cn:80    183.60.215.36:36970     TIME_WAITtcp    0  4166 coolshell.cn:80    61.148.242.38:30901     ESTABLISHEDtcp    0   1 coolshell.cn:80    124.152.181.209:26825    FIN_WAIT1tcp    0   0 coolshell.cn:80    110.194.134.189:4796    ESTABLISHEDtcp    0   0 coolshell.cn:80    183.60.212.163:51082    TIME_WAITtcp    0   1 coolshell.cn:80    208.115.113.92:50601    LAST_ACKtcp    0   0 coolshell.cn:80    123.169.124.111:49840    ESTABLISHEDtcp    0   0 coolshell.cn:80    117.136.20.85:50025     FIN_WAIT2tcp    0   0 :::22         :::*            LISTEN

下面是最简单最常用的awk示例,其输出第1列和第4例

  • 其中单引号中的被大括号括着的就是awk的语句,注意,其只能被单引号包含。
  • 其中的$1..$n表示第几例。注:$0表示整个行。
    $ awk '{print $1, $4}' netstat.txtProto Local-Addresstcp 0.0.0.0:3306tcp 0.0.0.0:80tcp 127.0.0.1:9000tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp coolshell.cn:80tcp :::22

我们再来看看awk的格式化输出,和C语言的printf没什么两样:

$ awk'{printf "%-8s %-8s %-8s %-18s %-22s %-15s\n",$1,$2,$3,$4,$5,$6}'netstat.txtProto  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    coolshell.cn:80  124.205.5.146:18245  TIME_WAITtcp   0    0    coolshell.cn:80  61.140.101.185:37538  FIN_WAIT2tcp   0    0    coolshell.cn:80  110.194.134.189:1032  ESTABLISHEDtcp   0    0    coolshell.cn:80  123.169.124.111:49809 ESTABLISHEDtcp   0    0    coolshell.cn:80  116.234.127.77:11502  FIN_WAIT2tcp   0    0    coolshell.cn:80  123.169.124.111:49829 ESTABLISHEDtcp   0    0    coolshell.cn:80  183.60.215.36:36970  TIME_WAITtcp   0    4166   coolshell.cn:80  61.148.242.38:30901  ESTABLISHEDtcp   0    1    coolshell.cn:80  124.152.181.209:26825 FIN_WAIT1tcp   0    0    coolshell.cn:80  110.194.134.189:4796  ESTABLISHEDtcp   0    0    coolshell.cn:80  183.60.212.163:51082  TIME_WAITtcp   0    1    coolshell.cn:80  208.115.113.92:50601  LAST_ACKtcp   0    0    coolshell.cn:80  123.169.124.111:49840 ESTABLISHEDtcp   0    0    coolshell.cn:80  117.136.20.85:50025  FIN_WAIT2tcp   0    0    :::22       :::*          LISTEN

我们再来看看如何过滤记录(下面过滤条件为:第三列的值为0 && 第6列的值为LISTEN)

$ awk '$3==0 && $6=="LISTEN" ' netstat.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

其中的“==”为比较运算符。其他比较运算符:!=, <, < >=, < p>

 

我们来看看各种过滤记录的方式:

$ awk' $3>0 {print $0}'netstat.txtProto Recv-Q Send-Q Local-Address     Foreign-Address       Statetcp    0  4166 coolshell.cn:80    61.148.242.38:30901     ESTABLISHEDtcp    0   1 coolshell.cn:80    124.152.181.209:26825    FIN_WAIT1tcp    0   1 coolshell.cn:80    208.115.113.92:50601    LAST_ACK

如果我们需要表头的话,我们可以引入内建变量NR:

$ awk '$3==0 && $6=="LISTEN" || NR==1 ' netstat.txtProto 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 :::22         :::*            LISTEN

再加上格式化输出:

$ awk'$3==0 && $6=="LISTEN" || NR==1 {printf "%-20s %-20s %s\n",$4,$5,$6}'netstat.txtLocal-Address    Foreign-Address   State0.0.0.0:3306     0.0.0.0:*      LISTEN0.0.0.0:80      0.0.0.0:*      LISTEN127.0.0.1:9000    0.0.0.0:*      LISTEN:::22        :::*         LISTEN

内建变量

说到了内建变量,我们可以来看看awk的一些内建变量:

$0  当前记录(这个变量中存放着整个行的内容)$1~$n  当前记录的第n个字段,字段间由FS分隔FS  输入字段分隔符 默认是空格或TabNF  当前记录中的字段个数,就是有多少列NR  已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中。FNR  当前记录数,与NR不同的是,这个值会是各个文件自己的行号RS  输入的记录分隔符, 默认为换行符OFS  输出字段分隔符, 默认也是空格ORS  输出的记录分隔符,默认为换行符FILENAME  当前输入文件的名字

怎么使用呢,比如:我们如果要输出行号:

$ awk'$3==0 && $6=="ESTABLISHED" || NR==1 {printf "%02s %s %-20s %-20s %s\n",NR, FNR, $4,$5,$6}'netstat.txt01 1 Local-Address    Foreign-Address   State07 7 coolshell.cn:80   110.194.134.189:1032 ESTABLISHED08 8 coolshell.cn:80   123.169.124.111:49809 ESTABLISHED10 10 coolshell.cn:80   123.169.124.111:49829 ESTABLISHED14 14 coolshell.cn:80   110.194.134.189:4796 ESTABLISHED17 17 coolshell.cn:80   123.169.124.111:49840 ESTABLISHED

指定分隔符
$ awk 'BEGIN{FS=":"} {print $1,$3,$6}' /etc/passwdroot 0 /rootbin 1 /bindaemon 2 /sbinadm 3 /var/admlp 4 /var/spool/lpdsync5 /sbinshutdown6 /sbinhalt 7 /sbin

上面的命令也等价于:(-F的意思就是指定分隔符)

$ awk-F: '{print $1,$3,$6}'/etc/passwd

注:如果你要指定多个分隔符,你可以这样来:

awk-F '[;:]'

字符串匹配

$ awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt1    Local-Address  Foreign-Address State6    coolshell.cn:80 61.140.101.185:37538  FIN_WAIT29    coolshell.cn:80 116.234.127.77:11502  FIN_WAIT213   coolshell.cn:80 124.152.181.209:26825  FIN_WAIT118   coolshell.cn:80 117.136.20.85:50025   FIN_WAIT2$ $ awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt1    Local-Address  Foreign-Address State5    coolshell.cn:80 124.205.5.146:18245   TIME_WAIT6    coolshell.cn:80 61.140.101.185:37538  FIN_WAIT29    coolshell.cn:80 116.234.127.77:11502  FIN_WAIT211   coolshell.cn:80 183.60.215.36:36970   TIME_WAIT13   coolshell.cn:80 124.152.181.209:26825  FIN_WAIT115   coolshell.cn:80 183.60.212.163:51082  TIME_WAIT18   coolshell.cn:80 117.136.20.85:50025   FIN_WAIT2

上面的示例匹配FIN状态, 第二个示例匹配WAIT字样的状态。其实 ~ 表示模式开始。/ /中是模式。这就是一个正则表达式的匹配。

 

其实awk可以像grep一样的去匹配第一行,就像这样:

$ awk '/LISTEN/' netstat.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