linux三剑客之awk

awk

   
   
    简介:是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言的最大功能
          取决于一个人所拥有的知识。awk经过改进生成的新的版本nawk,gawk,现在默认linux系统下日常使用的是gawk,用命令可以查
          看正在应用的awk的来源(ls -l /bin/awk )
    名称由来:三位作者名字的首字母,Aho, Weinberger, Kernighan
    格式:
        awk [options] ‘program’ var=value file…
        awk [options] - f programfile var=value file…
        awk [options] 'BEGIN{ action;… } pattern{ action;… } END{action;… }' file ...
     awk通常组成:
         BEGIN语句块、能够使用模式匹配的通用语句块、END语句块
         program通常是被单引号或双引号中
    常用选项
        -F:指定分割符,默认为空白分隔符
        -v:定义变量,每个变量前添加-v
      
    基本格式:awk [options] 'program' file…
      
       program组成:patter{action}两个部分组成
           patter:决定动作的何时触发和触发事件
           (BEGIN,END)
          action对数据进行处理,放在{}内指明
          ( print, printf)
          
    分割符、域和记录
    • awk执行时, 由分隔符分隔的字段(域)标记$1,$2..$n称为域标识。 $0为所有域,注意:和shell中变量$符含义不同
    • 文件的每一行称为记录
    • 省略action,则默认执行 print $0 的操作。
    
    工作原理
        第一步:执行BEGIN{action;… }语句块中的语句
        第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{action;… }语句块,它逐行扫描文件,从第一行到最后一行重
        复这个过程,直到文件全部被读取完毕。
        第三步:当读至输入流末尾时,执行END{action;…}语句块
        BEGIN:语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常
            可以写在BEGIN语句块中
        END:语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它
            也是一个可选语句块
      pattern:语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取
              到的行, awk读取的每一行都会执行该语句块
     
       action动作
           print格式:print item1,item2
           (1)用逗号隔开,输入结果以空格分割
          (2)item的值可以是字符串(用双引号引起来)、变量、当前记录(行)的字段、数值、awk表达式
          (3)如果不写item默认打印$0
          
       awk 变量
           内置变量:
           FS:指定字段的分隔符,默认为空格
               awk -v FS=":" '{print $1}' file
               awk  -F  ":"  '{print $1}' file
           OFS:输出字段的分隔符,默认的为空白
               awk - v FS=‘:’ - v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd
           RS:输入记录分隔符, 指定输入时的换行符,原换行符仍有效
            awk -v RS=' ' ‘{print }’ /etc/passwd
           NF:字段数量
               awk  -F: '{print NF}' /etc/passwd
             NR:行号(多个文件时,将不单独统计每个文件的行号)
               awk  '{print NR,$0}' /etc/passwd
           FNR:分别显示每个文件的行号
               awk    '{print FNR,$0}' /etc/passwd /etc/fstab
            
           FILENAME:当前文件名
               awk '{print FILENAME}’ /etc/fstab 
                       
            ARGV:数组,保存的是命令行所给定的各参数
                awk ‘BEGIN {print ARGV[0]}’ /etc/fstab
        自动变量:
            (1) - v var=value
              变量名区分字符大小写             
            (2) 在program中直接定义
             awk - v test='hello gawk' '{print test}' /etc/fstab  :/etc/fstab有几行将会打印出几行‘hellow gawk’
                         awk - v test='hello gawk' 'BEGIN{print test}'
                         awk 'BEGIN{test="hello,gawk";print test}'  
                                    
        printf
          格式:printf "格式",item1,item2.....
                       (1) 必须指定FORMAT
                       (2) 不会自动换行,需要显式给出换行控制符, \n
                       (3) FORMAT中需要分别为后面每个item指定格式符                             
                          
          格式符:与item一一对应
              %c:显示字符的ASCII码
              %s:字符
              %d %i:数字十进制格式
              %f:浮点型
              %e %E:科学计数法表示
              %u:显示无符号整数
              %g %G:科学计数法表示或者浮点型表示
              %%:显示%本身
              
          修饰符:
             #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度, %3.1f
             - : 左对齐(默认右对齐) %-15s
             +:显示数值的正负符号 %+d
             
          awk实例:
              awk -F: '{printf "username:%-15s \t  UID:%+4d\n",$1,$3}' /etc/passwd   
              
        awk操作符
        
            算术操作符:
             x+y, x- y, x*y, x/y, x^y, x%y
                    - x: 转换为负数
                    +x: 转换为数值 
                    [root@mycentos6 ~]# awk -v a=10 -v b=10  'BEGIN{print a + b}'
                    20
                    [root@mycentos6 ~]# 
                      
                    字符串操作符:没有符号的操作符,字符串连接  
                    [root@mycentos6 ~]# awk -v a=10 -v b=10  'BEGIN{print a  b}'
                    1010
                    [root@mycentos6 ~]#       
                  
       赋值操作符:
                    =, +=, - =, *=, /=, %=, ^=
                    ++, --  
                 比较操作符:
                    >, >=, <, <=, !=, ==
                 模式匹配符:
                    ~:左边是否和右边匹配包含
                    !~:是否不匹配
                 [root@mycentos6 ~]# cat /etc/passwd |awk '$0 !~ /root/' |wc -l
                    35
                [root@mycentos6 ~]# cat /etc/passwd |awk '$0 !~ /^root/' |wc -l
                    36
                [root@mycentos6 ~]#
                
                 逻辑操作符: &&, ||, !   
                     示例:注意{}位置
                    • awk –F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
                    • awk - F: '$3 ==0 || $3>=1000 {print $1 }' /etc/passwd 
                    • awk - F: ‘!($3==0) {print $1 }' /etc/passwd
                    • awk - F: '!($3>=500) {print $3}}' /etc/passwd
                条件表达示    
                    selector?if- true- expression:if- false- expression
                    selector:为条件,如果为真执行?后面的语句,如果为假则执行:后面的语句
                    示例:
                    [root@mycentos6 ~]# awk -F: '{$3>=500?type="commonuser":type="systemuser"; \ :分行显示,可以直接写一行
                    > printf "%-10s \t %s\n ",$1,type}' /etc/passwd    
                              
    PATTERN
           
              作用:根据pattern条件,过滤匹配的行,再做处理    
               (1)如果未指定: 空模式,匹配每一行         
               (2) /regular expression/:仅处理能够模式匹配到的行,需要用 / /括起来
                    awk '/^UUID/{print $1}' /etc/fstab
                    awk '!/^UUID/{print $1}' /etc/fstab    
              (3) relational expression: 关系表达式;结果有“真”有“假”;结果为“
                    真”才会被处理;
                   真:结果为非0值,非空字符串 ‘0,1’:结果为真
                   假:结果为空字符串  
              示例:
                   [root@mycentos6 ~]# awk -F: '$NF=="/bin/bash"{print $1 ,$3}' /etc/passwd
                    root 0
                    mysql 27
                    user1 500
                    user2 501
                    user3 502
                   [root@mycentos6 ~]# 
                   
                   [root@mycentos6 ~]# seq 10 |awk 'i=!i'
                    1
                    3
                    5
                    7
                    9
                    [root@mycentos6 ~]# 
             (4) line ranges: 行范围
                startline,endline: /pat1/,/pat2/ 不支持直接给出数字格式
                awk - F: '/^root/,/^nobody/{print $1}' /etc/passwd
                awk - F: '(NR>=2&&NR<=10){print $1}' /etc/passwd      
                    
              [root@mycentos6 ~]# awk -F: '/^root/,/^user2/{print $1}' /etc/passwd       
              
              5) BEGIN/END模式
                BEGIN{}: 仅在开始处理文件中的文本之前执行一次 使用于打印标题等
                END{}:仅在文本处理完成之后执行一次

    

    示例:
        1、awk - F : 'BEGIN {print "USER USERID"} {print$1":"$3} END{print "end file"}' /etc/passwd
        2、awk - F: 'BEGIN{print " USER UID \n ---------------- "}{print $1,$3}'END{print "=============="}
            /etc/passwd
   
   
    awk  action分类
        (1) Expressions:算术,比较表达式等
        (2) Control statements: if, while等
        (3) Compound statements:组合语句
        (4) input statements
        (5) output statements: print等

    awk 控制语句:if else

   

      
     
    '{ if(condition) statement [else statement]}'
    '{if(condition1){statement1}else if(condition2){statement 2}else{statement3}}'
     
    示例:
         1、判断磁盘使用率,如果大于70,打印磁盘名
         2、判断成绩

      1、

        9.png

      2、

        10.png

         11.png

    while 语句: 

     while循环:语法 while(condition) statement
      使用场景:对一行内的多个字段逐一类似处理时使用
           对数组中的各元素逐一处理时使用 
           
     示例:

    12.png 

  13.png

    awk中do …while语句

        语法: do statement while(condition)    
      意义:无论真假,至少执行一次循环体
         示例:
         awk 'BEGIN{ total=0;i=0;do{total+=i;i++;}while(i<=100);print total}'

    14.png   

    

    for 语句:

       
        语法: for(expr1;expr2;expr3) statement
            for(variable assignment;condition;iteration process) {forbody}
        特殊用法:能够遍历数组中的元素;
            语法: for(var in array) {for- body}
            
        示例: awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print$i,length($i)}}' /etc/grub2.cfg

    

    性能比较:

        

       

               #time (awk 'BEGIN{total=0;for(i=0;i<=10000;i++){total+=i;};print total;}')
        #time(total=0;for i in $(seq 10000);dototal=$(($total+i));done;echo $total)

        blob.png

       关键字:time

        blob.png     

    awk控制语句

        
        switch语句
        语法: switch(expression) {case VALUE1 or /REGEXP/:statement; case VALUE2 or /REGEXP2/: statement;...; default: statement}
        
        break和continue    
        next:提前结束对本行处理而直接进入下一行处理( awk自身循环)

    blob.png

    blob.png

    blob.png

    awk数组:

        关联数组: array[index- expression]
            index- expression:
            (1) 可使用任意字符串;字符串要使用双引号括起来
            (2)如果某数组元素事先不存在,在引用时, awk会自动创建此元素,并将其值初始化为“空串”
            (3)若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
            
            awk '!a[$0]++' dupfile:过滤掉重复行 ,我用以下方法写也许更容易理解

        blob.png

       blob.png

     1、要理解:awk '!a[$0]++'先看下面程序,数组在默认不给值时,当对空值数组进行++操作,数组的值会自动+1

        blob.png 

    2、详细说明!a[$0]++的值 当awk读取f1时, a[111]值为空——>!a[111]值为1 ,因此打印$0;a[111]++;a[111]值为2;当再遇见a[111],也就是相同的两行

      a[111]=2;!a[111]=0 ;一次不在打印111这一行,a[111]++ ;a[111]=3     

    

    awk数组 :

     
      若要遍历数组中的每个元素,要使用for循环
      格式:for(var in array) {for- body}
      注意: var会遍历array的每个索引,所以var的值也就是索引的值

      实例1、
      blob.png

     实例2、查看每个tcp状态的连接数

       blob.png  

     实例3、查看每个ip地址访问http链接数

        blob.png

        blob.png

    awk函数:        

        数值处理:
        rand():返回0和1之间一个随机数 ,必须加srand()结合使用

        awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'

        blob.png

        

        字符串处理:

        • length([s]):返回指定字符串的长度

        blob.png

        

       sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s

        blob.png   

      gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容

        blob.png     

      split(s,array,[r]):以r为分隔符切割字符s,并将切割后的结果保存至array所表示的数组中

    blob.png

        

      自定义函数格式:

        格式:
        function name ( parameter, parameter, … ) {
        statements
        return expression

        }
     blob.png

    awk中调用shell命令      

        system命令
        空格是awk中的字符串连接符,如果system中需要使用 awk中的变量可以使用空格分隔,或者说除了 awk的变量外其他一律
        用 ""引用起来。
        awk BEGIN'{system("hostname") }'

        awk 'BEGIN{score=100; system("echo your score is " score) }'

    blob.png

    
    将awk程序写成脚本,直接调用或执行

       

        #cat f1.awk
        if($3>=1000)print $1,$3}

        #awk – F: – f f1.awk /etc/passwd

        

        #cat f2.awk
        #!/bin/awk –f
        #this is a awk script
        {if($3>=1000)print $1,$3}
        #chmod +x f2.awk

        #f2.awk –F: /etc/passwd

    

    向awk脚本传递参数      

        格式:awkfile var=value var2=value2… Inputfile        

        示例:
        #cat test.awk
        #!/bin/awk –f
        {if($3 >=min && $3<=max)print $1,$3}
        #chmod +x test.awk

        #test.awk – F: min=100 max=200 /etc/passwd

        blob.png

    练习题:

        1、 统计/etc/fstab文件中每个文件系统类型出现的次数

        blob.png

        2、 统计/etc/fstab文件中每个单词出现的次数;
        blob.png

        

原创文章,作者:wangnannan,如若转载,请注明出处:http://www.178linux.com/47860