awk笔记

awk笔记

AWK 简明教程进行总结。

准备工作:

copy下面这个文件到你的Linux主机上,命名为test.txt(这个命名随意)。

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      23353/sshd          
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      23106/docker-proxy  
tcp        0      0 127.0.0.1:3306          127.0.0.1:55510         ESTABLISHED 23106/docker-proxy  
tcp        0      0 172.18.0.1:49262        172.18.0.2:3306         ESTABLISHED 23106/docker-proxy  
tcp        0      0 172.18.0.1:49126        172.18.0.2:3306         ESTABLISHED 23106/docker-proxy  
tcp        0      0 172.18.0.1:49270        172.18.0.2:3306         ESTABLISHED 23106/docker-proxy  
tcp        0      0 127.0.0.1:3306          127.0.0.1:55502         ESTABLISHED 23106/docker-proxy  
tcp        0      0 172.18.0.1:49314        172.18.0.2:3306         ESTABLISHED 23106/docker-proxy  
tcp        0      0 172.17.0.17:22          182.254.227.79:55316    ESTABLISHED 5859/sshd: [accepte 
tcp        0      0 127.0.0.1:3306          127.0.0.1:55468         ESTABLISHED 23106/docker-proxy  
tcp        0      0 172.18.0.1:49218        172.18.0.2:3306         ESTABLISHED 23106/docker-proxy  
tcp        0      0 172.18.0.1:49284        172.18.0.2:3306         ESTABLISHED 23106/docker-proxy  
tcp        0     64 172.17.0.17:22          203.168.21.218:39785    ESTABLISHED 4359/sshd: root@pts 
tcp        0      0 127.0.0.1:3306          127.0.0.1:55406         ESTABLISHED 23106/docker-proxy  
tcp        0      0 127.0.0.1:3306          127.0.0.1:55314         ESTABLISHED 23106/docker-proxy  
tcp        0      0 127.0.0.1:3306          127.0.0.1:55484         ESTABLISHED 23106/docker-proxy
image-20210817151449573

awk的帮助手册

[root@VM-0-17-centos test_awk]# awk --help
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:          GNU long options: (standard)
        -f progfile             --file=progfile
        -F fs                   --field-separator=fs
        -v var=val              --assign=var=val
Short options:          GNU long options: (extensions)
        -b                      --characters-as-bytes
        -c                      --traditional
        -C                      --copyright
        -d[file]                --dump-variables[=file]
        -e 'program-text'       --source='program-text'
        -E file                 --exec=file
        -g                      --gen-pot
        -h                      --help
        -L [fatal]              --lint[=fatal]
        -n                      --non-decimal-data
        -N                      --use-lc-numeric
        -O                      --optimize
        -p[file]                --profile[=file]
        -P                      --posix
        -r                      --re-interval
        -S                      --sandbox
        -t                      --lint-old
        -V                      --version

To report bugs, see node `Bugs' in `gawk.info', which is
section `Reporting Problems and Bugs' in the printed version.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

Examples:
        gawk '{ sum += $1 }; END { print sum }' file
        gawk -F: '{ print $1 }' /etc/passwd
[root@VM-0-17-centos test_awk]# 

awk语句

awk命令后面通常紧跟一个由单引号括起的语句。

在语句中有一些特殊的变量:

  • 第n列:$n,下标从1开始算起。(输出多列的时候可以用,隔开每列,显示的时候会使用1个空格来隔开)

    image-20210817151850123
  • 一行:$0

    image-20210817151912189

格式化输出

使用printf格式化输出,跟C语言的printf差不多。

注:printf不会在每行后添加换行符,print则会。

image-20210817152230638

过滤记录

过滤条件:第三列大于0且第六列是LISTEN的记录

[root@VM-0-17-centos test_awk]# awk '$3>0 || $6=="LISTEN"' test.txt 
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      23353/sshd          
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      23106/docker-proxy  
tcp        0     64 172.17.0.17:22          203.168.21.218:39785    ESTABLISHED 4359/sshd: root@pts

awk的比较运算符

==!=><>=<=

awk的逻辑运算符:

&&||

过滤记录 + 格式化输出

过滤条件:第六列是LISTEN的记录

[root@VM-0-17-centos test_awk]# awk '$6=="LISTEN" {printf "协议是:%+5s, 当前状态:%+8s, 当前进程:%+20s\n", $1, $6, $7}' test.txt 
协议是:  tcp, 当前状态:  LISTEN, 当前进程:         7806/nginx:
协议是:  tcp, 当前状态:  LISTEN, 当前进程:         7806/nginx:
协议是:  tcp, 当前状态:  LISTEN, 当前进程:          23353/sshd
协议是:  tcp, 当前状态:  LISTEN, 当前进程:         7806/nginx:
协议是:  tcp, 当前状态:  LISTEN, 当前进程:  23106/docker-proxy

awk的内建变量

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

指定分隔符

将文件中的字段分隔符设置为:

先查看下原文件

image-20210817154535836

使用awk指定分隔符。

image-20210817154437160

上图的命令为:awk 'BEGIN{FS=":"} {print $1, $3, $6}' /etc/passwd

该命令也等价于:awk -F: '{print $1, $3, $6}' /etc/passwd

image-20210817154733844

当使用多个分隔符时,可以这样awk -F '[;:]'

案例:指定\t为字段分隔符和\n\n为行分隔符输出。

image-20210817155340245

字符串匹配

案例一:查找第七列中包含nginx的记录。

[root@centos test_awk]# awk '$7 ~ /nginx/ || NR == 1 {print NR, $1, $4, $7}' OFS="\t" test.txt
1       Proto   Local   Address
2       tcp     0.0.0.0:8080    7806/nginx:
3       tcp     0.0.0.0:80      7806/nginx:
5       tcp     0.0.0.0:443     7806/nginx:

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

案例二:查找第七列中不包含nginx的记录。

[root@VM-0-17-centos test_awk]# awk '$7 !~ /nginx/ || NR == 1 {print NR, $1, $4, $7}' OFS="\t" test.txt
1       Proto   Local   Address
4       tcp     0.0.0.0:22      23353/sshd
6       tcp     0.0.0.0:3306    23106/docker-proxy
7       tcp     127.0.0.1:3306  23106/docker-proxy

模式取反:在~前面加个!符号即可。

案例二:查找记录中包含LISTEN。

[root@VM-0-17-centos test_awk]# awk '/LISTEN/' test.txt 
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      23353/sshd          
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      7806/nginx: master  
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      23106/docker-proxy 

当只需要模式匹配时,可以不用在//前面加~符号,取反同理,只需要!//即可。

image-20210817160624717

拆分文件

image-20210817170026403

上图就是把输出的每一行内容都重定向(>)到$6中,可以看到目录下有两个生成的文件:LISTENESTABLISHED,其实就是$6字段中去重后的结果。对应的文件内容就是test.txt中每一行$6中包含对应的字符串(即:LISTENESTABLISTEN)的每一行记录。

ESTABLISTEN文件中的内容:

image-20210817173105132

LISTEN文件中的内容:

image-20210817173145087

案例:把第4列和第5列输出到output.txt文件中,不包含首行。

[root@VM-0-17-centos test_awk]# awk 'NR!=1{print $4, $5 > "output.txt"}' test.txt 
[root@VM-0-17-centos test_awk]# cat output.txt 
0.0.0.0:8080 0.0.0.0:*
0.0.0.0:80 0.0.0.0:*
0.0.0.0:22 0.0.0.0:*
0.0.0.0:443 0.0.0.0:*
0.0.0.0:3306 0.0.0.0:*

案例:将nginx进程的内容输出到nginx.txt中,docker进程的内容输出到docker.txt,其他进程输出到other.txt中

[root@VM-0-17-centos test_awk]# netstat -nap | awk '{if($7 ~ /nginx/) print > "nginx.txt";
> else if($7 ~ /docker/) print > "docker.txt";
> else print > "other.txt"}'
[root@VM-0-17-centos test_awk]# ls -l
total 24
-rw-r--r-- 1 root root  2390 Aug 17 17:41 docker.txt
-rw-r--r-- 1 root root   303 Aug 17 17:41 nginx.txt
-rw-r--r-- 1 root root 10363 Aug 17 17:41 other.txt
-rw-r--r-- 1 root root  2020 Aug 17 15:14 test.txt

注:使用if-else-语句来实现分支控制,使用;来分行,你学废了吗?

image-20210817174302035

统计

案例一:统计当前路径下字节码文件的总大小

[root@VM-0-17-centos rule]# ls -l *.class | awk '{sum+=$5} END {print sum}'
1382

案例二:统计当前TCP连接中各个连接的状态

[root@VM-0-17-centos rule]# netstat -napt | awk 'NR!=1{a[$6]++} END {for (i in a) print i ", " a[i];}'
LISTEN, 8
ESTABLISHED, 34
Foreign, 1
TIME_WAIT, 4

awk脚本

关键字

  • BEGIN
  • END

案例:统计学生成绩里面各科成绩总分和平均分

  1. 准备工作(把下列内容写入到score.txt文件中)

    [root@VM-0-17-centos test_awk]# cat score.txt 
    Marry   2143 78 84 77
    Jack    2321 66 78 45
    Tom     2122 48 77 71
    Mike    2537 87 97 95
    Bob     2415 40 57 62
    
  2. 编写awk脚本

    [root@VM-0-17-centos test_awk]# cat cal.awk 
    #!/bin/awk -f
    
    #运行前
    BEGIN {
            math = 0
            english = 0
            computer = 0
            printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
            printf "---------------------------------------------\n"
    }
    #运行中
    {
            math += $3
            english += $4
            computer += $5
            printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
    }
    #运行后
    END {
            printf "---------------------------------------------\n"
            printf "  TOTAL:%10d %8d %8d \n", math, english, computer
            printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
    }
    
  3. 运行(也可以这样运行:./cal.awk score.txt

    [root@VM-0-17-centos test_awk]# awk -f cal.awk score.txt 
    NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL
    ---------------------------------------------
    Marry  2143     78       84       77      239
    Jack   2321     66       78       45      189
    Tom    2122     48       77       71      196
    Mike   2537     87       97       95      279
    Bob    2415     40       57       62      159
    ---------------------------------------------
      TOTAL:       319      393      350 
    AVERAGE:     63.80    78.60    70.00
    
posted @ 2021-08-17 21:41  yghr  阅读(71)  评论(0)    收藏  举报