awk

作者: tracy_668 | 来源:发表于2018-09-09 11:58 被阅读15次

    awk是一个强大的文本分析工具,简单地说,它是把文件逐行读入,以空格为默认分割符将每行切片,切开的部分再进行分析、处理。

    使用方法

    awk 'pattern + {action}'  filenames
    

    案例说明:

    wusong@ubuntu:~$ last -n 5
    wusong   pts/9        192.168.58.1     Sat Sep  8 19:06   still logged in
    wusong   pts/9        192.168.58.1     Sat Sep  8 06:47 - 18:11  (11:24)
    wusong   pts/10       192.168.58.1     Fri Sep  7 20:24 - 21:21  (00:56)
    wusong   pts/9        192.168.58.1     Fri Sep  7 19:26 - 21:21  (01:55)
    wusong   pts/9        192.168.58.1     Fri Sep  7 06:45 - 18:56  (12:11)
    
    wtmp begins Mon Sep  3 17:27:36 2018
    
    wusong@ubuntu:~$ last -n 5 |awk '{print $1}'
    wusong
    wusong
    wusong
    wusong
    wusong
    
    wtmp
    

      awk会读取有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,0表示所有的域,1表示第一个域,$n表示第n个域。

    cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
    name,shell
    root,/bin/bash
    daemon,/bin/sh
    bin,/bin/sh
    sys,/bin/sh
    ....
    blue,/bin/nosh
    

     如果有BEGIN,就会先执行BEGIN,然后读取文件,读入有\n换行分割符的一条记录,对每条记录执行action,直到所有的记录都读完,最后执行end操作。

    awk -F: '/root/' /etc/passwd // 搜索含有root关键字的行
    root:x:0:0:root:/root:/bin/bash
    awk -F: '/root/{print $7}' /etc/passwd
    /bin/bash
    

    awk内置变量

    ARGC 命令行参数个数
    ARGV 命令行参数排列
    ENVIRON 支持队列中系统环境变量的使用
    FILENAME awk浏览的文件名
    FNR 浏览文件的记录数
    FS 设置输入域分隔符,等价于命令行 -F选项
    NF 浏览记录的域的个数
    NR 已读的记录数
    OFS 输出域分隔符
    ORS 输出记录分隔符
    RS 控制记录分隔符

    wusong@ubuntu:~$ awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
    filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
    filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/usr/sbin/nologin
    filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/usr/sbin/nologin
    filename:/etc/passwd,linenumber:5,columns:7,linecontent:sync:x:4:65534:sync:/bin:/bin/sync
    filename:/etc/passwd,linenumber:6,columns:7,linecontent:games:x:5:60:games:/usr/games:/usr/sbin/nologin
    filename:/etc/passwd,linenumber:7,columns:7,linecontent:man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
    filename:/etc/passwd,linenumber:8,columns:7,linecontent:lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
    filename:/etc/passwd,linenumber:9,columns:7,linecontent:mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
    
    可以使用printf代替print,让代码更加简洁
     awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
    

    awk除了内置变量,还可以自定义变量。

    • 统计/etc/passwd的账户人数
    awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
    
    • 统计某个文件夹下的文件占用的字节数
    wusong@ubuntu:~$ ls -l | awk 'BEGIN {size=0;} {size=size+$5;}END{print "size is", size}'
    size is 63307
    wusong@ubuntu:~$ ls -l | awk 'BEGIN {size=0;} {size=size+$5;}END{print "size is", size/1024/1024 " M"} '
    size is 0.0603743 M  // 不包括文件夹的子目录
    
    • awk 使用数组
    awk -F: 'BEGIN{count=0;} {name[count]=$1; count++;} END { for (i=0;i<NR;i++) print i, name[i]}' /etc/passwd
    

    几个小例子

    • 统计tcp连接状态
    wusongs-MacBook-Pro:~ wusong$ netstat -n | awk '/^tcp/{++test[$NF]} END {for (a in test) print a, test[a]}'
    CLOSE_WAIT 3
    TIME_WAIT 1
    ESTABLISHED 28
    

      S[]定义了一个名叫S的数组,在awk中,数组下标通常从 1 开始,而不是 0。
      NF当前记录里域个数,默认以空格分隔,如上所示的记录,NF域个数等于6
      $NF表示一行的最后一个域的值,$NF也就是$6,表示第6个字段的值,也即SYN_RECV或TIME_WAIT等。
      S[$NF] 表示数组元素的值,如上所示的记录,就是S[TIME_WAIT]状态的连接数++S[$NF]表示把某个数加一,如上所示的记录,就是把S[TIME_WAIT]状态的连接数加1
      END for(key in S)遍历S[]数组 print key,”\t”,S[key],打印数组的键和值,中间用\t制表符分割,显示好一些。

    • 统计apache日志单ip访问请求数排名
    awk '{++S[$1]} END {for(i in S) print i, S[i]}' access.log | sort -k2 -r
    10.0.0.41 3
    10.0.0.47 2
    10.0.0.46 2
    10.0.0.42 2
    10.0.0.43 1
    
    
    • 查看linux系统上的所有用户
    wusong@ubuntu:~$ awk 'BEGIN{
        FS=":"
        printf("%-10s%-20s\n", "UserName", "HomeDir")
        print "=============================="
    }
    {
        printf("%-10s%-20s\n", $1, $6)
    }
    END{
        print "=============================="
        printf("User(s):%d\n", NR)
        print "=============================="
    }' /etc/passwd
    

    也可以将上述脚本写入listUser.awk这个文件,然后在命令行中执行:

    awk -f listUser.awk /etc/passwd
    

    透过现象看本质

    image.png

    上图为awk的基本流程,awk分为三个部分:

    • BEGIN(必须大写),初始化模块,进行分隔符的定义,初始化一些变量等,它在数据处理部分之前执行,且只执行一次,BEGIN模块是可选的。
    • 数据处理模块。这一部分是awk脚本的核心部分,它是一对以pattern与大括号括起来的action组合而成,两者可能会出现以下组合:
      • pattern {action} :记录(每行为一个记录)匹配对应的模式,则执行大括号中的操作
      • pattern 记录匹配所有的模式,直接打印记录。
      • {action} 对每一条记录都执行大括号中的操作
    • 数据处理模块会循环读取待处理文件中的记录,读一条处理一条,处理完再读下一条。
    • END(必须大写),最后的收尾处理模块。它会在所有的数据处理完毕后执行,END模块同BEGIN一样只执行一次并且也是可选的。

    小结

    本文主要介绍了awk的基本用法和一些小的案例以及awk流程分析,awk是一种功能极其强大的文本分析工具,值得深入研究。

    相关文章

      网友评论

          本文标题:awk

          本文链接:https://www.haomeiwen.com/subject/elprgftx.html