zoukankan      html  css  js  c++  java
  • 三十一、Gawk基础入门

    AWK:Aho Weinberger Kernighan

    awk :报告生成器、格式化文本输出

    一、gawk - pattern scanning and processing language

      基本用法:gawk [optins] 'program' FILE ...
    
        语句之间用分号分割
      选项:
        -F ' ' :指明输入时用到的字段分隔符
        -v var=value :自定义变量
      PATTERN: 定义读入哪些行时对行处理
      ACTION :对行如何处理,文本格式化输出:print, printf 多个语句之间用“;”分开

    二、工作模式:

      默认读取全文 ,PATTERN只是决定能处理的行,同sed

      读取文件一行,以-F指定的输入字段分隔符切割字段,并且将每一片记录与awk内建的变量中,$1,$2,$3,...$#,$@,$0 ,支持行的字段条件判断,判断后此行满足时,显示此行的部分字段或对行内循环

    注:默认以空格分隔,不管空白字符多少都只认为一个空白字符

    三、变量

    3.1、内建变量

    a)FS:input field seperator 默认为空白字符    

     e.g      awk '{print $1}' /etc/passwd  

            awk -v FS=":"  '{print $1,$3}' /etc/passwd

    b)、OFS :output field seperator 默认为空白字符

        

    c) 、RS:Raw Seperator   输入的换行符,默认为$

    d)、ORS:Output Raw Seperator   输出时的换行符,默认为$   

        awk -v RS=":" -v  ORS="^_^" '{print $1,$3}' /etc/passwd

    e)、NF :Number  of Raw 字段数量

      $NF:每行最后一个字段 

    [root@redhat wilsontest]# awk '{print NF,NR,$0}END{print FILENAME}' filetest
    2 1 hello wilson
    1 2 world
    1 3 linux
    1 4 oracle
    1 5 C++
    
    说明:
    第一列NF输出读取记录的域的个数;
    NR表示已经读取的记录数;
    $0实际就是把记录输出出来;
    
    $0就表示一个记录,$1表示记录中的第一个字段。
    一般 print $0 就是打印整行内容($0前面不需要反斜杠),print $1表示只打印每行第一个字段。

    f)、NR :Number of Filed   文件中的行数

        #awk '{print NR}' FILE

        #awk '{print NR}' FILE1   FILE2 ...  对行进行累计计数

    g)、FNR :对每一个文件单独计数

       #awk '{print FNR}' FILE1 FILE2 ...   对每个文件分别计行数

    h)、FILENAME:显示当前被处理的文件的文件名

      #awk '{print  FILENAME}' FILE1  FILE2

    I)、ARGC : 命令行中给定的参数的个数

       #awk  '{print  ARGC}'  FILE1  FILE2

    K)、ARGV :数组,保存的是命令行所给定的各参数

       

    e.g

      awk '{print ARGV[0]}' /etc/fstab /etc/issue =====》awk
      awk '{print ARGV[1]}' /etc/fstab /etc/issue ======》/etc/fstab
      awk '{print ARGV[2]}' /etc/fstab /etc/issue ======》/etc/issue

     

    3.2、自定义变量

    a) -v name="Obama"
      变量名一样区分字符大小写
    
    b) 在program中直接定义   {name
    ="value";print name}
      注:变量不能用$符,$符号表示字段
        变量用能用"" ,""中的变量不会被替换

    四、ACTION

    4.1、print -----输出内容之后自动换行

    print  item1,item2,...
    
      要点:
        a) 逗号分隔符
        b) 默认输出分隔符为空白字符
        c) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式
         字符串 :"STRING"
         变量: 不能被引号包含
         即放在引号之内当做字符串,放在引号之外才能做变量替换
        d) 如省略item ,相当于{print} ==》 {print $0}

      

     4.2、printf-----可以自定义输出的模式,另外输出内容之后不自动换行

      文本格式化输出:printf "FORMAT" ,item1,item2, ...

      a)FORMAT是必须要输出

      b) 不会自动换行,需要给出换行控制符:

      b)format中需要分别为后面的每个item指定一个格式化符号

    格式符:

    %c  : 显示字符的ASCII码

    %d, %i :显示为十进制整数

    %e :科学计数法 数值显示

    %f : 显示为浮点数

    %g,%G :以科学计数法或浮点形式显示数值

    %s : 显示字符串

    %u :无符号整数

    %% :显示%自身

    修饰符 :

    #[.#] :第一数字控制显示的宽度;第二个#表示小数点后的精度

    - :左对齐。默认为右对齐

    + : 显示数值的符号

    e.g

     awk -F : '{printf "%s,%d ",$1,$2}' /etc/passwd

     awk -F : '{printf "%-15s,%d ",$1,$3}' /etc/passwd

      

      awk -F : '{printf "Username:%-15s UID:%d ",$1,$3}' /etc/passwd

    3、操作符

    wKioL1m5Pp_Q3M6cAAAmQmDnIbY928.png

    wKiom1m5PrnxjqQyAAAvONOQYGw505.png

    函数调用:函数名(argu1,argu2,...)

      function_name(arg1,arg2,...)   规范式

    内建条件表达式:

      selector?if-ture-expression:if-false-expression

         selector :条件表达式

          ?:看它为真或假

          if-ture-expression :条件表达式为真时,执行

          if-false-expression :条件表达式为假时,执行

       

    awk -F: '{$3>=1000?usertyep="Common User":usertype="Sysadmin or SysUser";printf "%15s:%s ",$1,usertype}' /etc/passwd

    、PATTERN地址定界功能 :'PATTERN{ACTION STATEMENT}'

    5.1、empty :处理文本的每一行,sed空模式,每一行都会进行script

    5.2、/regex-pattern/ 仅处理能够被此处的模式所匹配到的行

       #awk  '/^UUID/{print $1}' /etc/paawd

     5.3、relational expression : 关系表达式,结果有“真”有“假”  ---结果为“真”才会被处理

         真:结果为非0值,非空字符串

           0表示假;空串为假

       #awk  -F ':'  ‘$3>=1000{print $1,$2}’   /etc/passwd    显示用户id大于1000的用户名

        #awk  -F ':'  '$NF=="/bin/bash" {print $1,$NF}’   /etc/passwd  

    5.4、模式符号 (所制定要匹配的字符要用 “//” 圈起来)

      显示用户shell为bash

        #awk  -F ':'  '$NF~/bash$/ {print $1,$NF}’   /etc/passwd  

    5.5、地址定界 

    line ranges :行范围

      #awk  -F ':'  '(NR >=10 && NR<=20) {print $1}’   /etc/passwd  

    /PATTERN/,/PATTERN/ :第一个指定的模式匹配开始 ---另一个指定模式匹配结束

      #awk  -F ':'  '/^root/,/^myuser/ {print $1}’   /etc/passwd  

    注:不支持直接给出数字的格式

    5.6、BEGIN/END模式  即表头/表尾

      BEGIN{program} :{}里面为代码段 仅在开始处理文件中每一行文本之前,仅执行一次;(表头

      END{program}  仅在文本处理完成后,命令结束前仅执行一次; (表尾)

     awk -F ":" 'BEGIN{print "username     uid 
    ================"}{print $1,$3}' /etc/passwd 

      awk -F ":" '{print "username uid ================" ;print $1,$3}' /etc/passwd   #每一行都会显示

    5.7、! 取反

    六、ACTION

    wKioL1m54PHTILyuAAAoxPTOdrY597.png

    wKioL1m54RqDlOrfAABE6HVfSJM312.png

    6.1 if-else 

    使用场景:对awk取得的整行或某个字段做条件判断

    语法:
    {if
    (condition) {true-statement}} 或 if (condition) true-statement { if (condition) {true-statement} else {false-statement} }
    e.g
    id号大于1000为普通用户 # awk
    -F ':' '{if ($3>500){print $1,$3}}' /etc/passwd # awk -F ':' '{if ($3>500){printf "%15s %-d ",$1,$3}}' /etc/passwd

    awk -F: '{if($3>1000){printf "Common user:%s ",$1} else {printf "Root or System:%s ",$1}}' /etc/passwd

    最后一个字段的行/bin/bash结尾
    # awk -F ':' '{if ($NF == "/bin/bash"){print $1,$3}}' /etc/passwd
    # awk -F ':' '{if ($NF ~ /<bash$/){print $NF}}' /etc/passwd
    每行字段数大于5个,显示行,否则不显示
    # awk -F ':' '{if (NF>5){print $0}}' /etc/passwd
    显示文件系统使用结果>80则显示

     df -h|awk -F "%" '/^/dev/{print $1}'|awk '{if($NF>20){print $1}}'   条件过滤

    # df -hP | awk -v FS="%" '!/^File/{print $1}' | awk '{if ($NF>80){print $1}}'

    6.2、while  

    使用场景:对一行内的多个字段逐一处理时使用;对数组中各元素逐一处理时使用

    while (condition) {true-statement}
    (condition) 判断条件
     {true-statement} 条件为真时,执行循环体
    
    length(arg1,arg2,...) 显示字段的长度

    a)对整个一行中的各字段,显示各字段内容和字段中包含的字段的个数

    思路: awk '{print length($i)}' FILE
    i表示每个字段即可
    #awk '/^[[:space:]]*linux16/{i=1;while(i<NF) {print $i,length($i);i++ }}' /tmp/grub2.cfg  
    linux16 7
    /boot/vmlinuz-3.10.0-957.27.2.el7.x86_64 40
    root=UUID=eb448abb-3012-4d8d-bcde-94434d586a31 46
    ro 2
    crashkernel=auto 16
    net.ifnames=0 13
    idle=halt 9

    b)循环嵌套if条件判断

    对整个一行中的各字段,字段大于等于7才显示字段内容和字段中包含的字段的个数

    #awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)};i++}}' ./grub2.cfg 
    linux16 7

    6.3、do-while循环

    do {true-statement} while (condition)
    意义:至少执行一次循环体
    # awk '{i=1;do {print $i,length($i);i++} while (i<=NF)}' /etc/issue

    6.4   for 循环

    for (控制变量初始化;控制变量条件表达式;控制变量的修正表达式) {statement}
    for (variable assignment;condition;iteration process) {for-body}

    #awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' ./grub2.cfg
    linux16 7

    #awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {if(length($i)>=16) print $i,length($i)}}' ./grub2.cfg
    /boot/vmlinuz-3.10.0-957.27.2.el7.x86_64 40

    注:循环体中嵌套单分支if语句 ,单分支if的statement的{} 可省略

    特殊用法:能够遍历数组中的元素

      语法:for(var in array) {for-body}

    6.5switch语句 多分支if

    字符串比较使用(awk 不常用)

    switch (expression) (case VALUE1 or /REGEXP1/:statement;case VALUE2 or /REGEXP2/:statement;...; default:statemet)
    表达式 == value1 或 表达式 ~ /REGEXP1
    default:statemet ==相当于bash语句case中 最后*)statemet;
    

    6.6 break [n] 或 continue---提前结束本轮循环直接进入下一个循环(无非处理的时下一个字段而已)

    显示奇数字段
    # awk -F ':' '{i=1;while (i<=NF){if (i%2==0) {i++;continue} else {print i,$i;i++}}}' /etc/passwd

    6.7 next(控制awk内生循环)-----提前结束对本行的处理直接进入下一行

    显示以/bin/bash结尾的行,非/bin/bash结尾的行next
    # awk -F ':' '{if ($NF != "/bin/bash"){next} else {print $0}}' /etc/passwd
    显示用户id号为偶数的用户
    # awk -F ':' '{if ($3%2 != 0){next} else {print $0}}' /etc/passwd

    6.8 、array数组

    关联数组:array_name[index-expression]
    
        index-expression(索引表达式)
           可使用任意字符串:字符串要使用双引号
           如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
           内部的字符串,必须要用到双引号,变量不能使用'""
    
    若要判断数组中是否存在某元素,要使用“index in array”格式进行
    
    赋值 weekdays["mon"]="Monday"
    
    显示 print weekdays["mon"]

    e.g 显示第一个元素 # awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Thuseday";print weekdays["mon"]}'

    遍历数组每个元素要使用for循环

    语法:for (var in array) {statement}
    
        var会遍历数组array[Index]的每个索引(下标index)
          var会逐一被赋值,为array的每一个Index
    # awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Thuseday";for(i in weekdays) {print weekdays[i]}}'

    场景:当多类数值,统计每一类数值各自出现多少次

    netstat -ant | awk '/^tcp>/'    # ^ 行开头; > 单词结尾

    1
    )查看所有状态 netstat -tan | awk '{print $NF}' 2)# netstat -tan | awk '/^tcp>/'{state[$NF]++} END{for (i in state){print i,state[i]}}'
    统计日志
    
    1)查看httpd是否被安装
    rpm -q httpd
    2) 启动httpd
    service httpd start
    3)httpd自带压力测试工具,ab
    ab -c 100 -n 1000 
    4)统计日志IP
    # awk '{count[$1]++}END{for (i in count){print i,count[i]}}' /var/log/httpd/access_log
    统计/etc/fstab文件中每个单词出现的次数(行内字段遍历)
    # awk '{i=1;while (i<=NF){count[$i]++;i++}}END{for (i in count){print i,count[i]}}' /etc/fstab
    # awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for (i in count){print i,count[i]}}' /etc/fstab
    统计/etc/fstab文件中每个文件系统类型出现的次数
    # awk '{print $3}' /etc/fstab 
    # awk '/^UUID/{fs[$3]++}END{for (i in fs){print i,fs[i]}}' /etc/fstab

    6.9、函数(了解)

    a)、内置函数

      1)、数值处理:

        rand():返回0和1之间的一个随机数

         #awk 'BEGIN{print rand()}'

    注:awk命令取随机时只要取得一次后,以后这个随机数字永远为第一次取得的随机数值

      2)、字符串处理:

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

        sub(r,s,[t]):[t] 可选参数

            以r表示的模式,来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容

            # awk -F ':' '{sub("o","O",$1);print}' /etc/passwd

       gsub(r,s,[t]):[t] 可选参数

         以r表示的模式,来查找t所表示的字符中的匹配的内容,并将其所有匹配到的内容替换为s所表示的内容

      split(s,a[,r]) 

         以r分割符切割字符串s,将切割后的结果保存至a所表示的数组中

     统计每一个ip建立ip的个数

    # netstat -tan|awk '/^tcp>/{split($5,ip,":");print ip[1]}'
    0.0.0.0
    0.0.0.0
    116.77.75.251
    100.100.30.26

      # netstat -tan|awk '/^tcp>/{split($5,ip,":");count[ip[1]]++}END{for (i in count){print i,count[i]}}'
      116.77.75.251 1
      0.0.0.0 2
      100.100.30.26 1

     
    统计每一个ip建立ip的个数
    # netstat -tnl | awk '!/^Proto/ && !/^Active/{split($5,state,":");ip[state[1]]++}END{for (i in ip){print i,ip[i]}}'

    https://www.cnblogs.com/sky-k/p/9435611.html

  • 相关阅读:
    css文字两端对齐,而且居中
    vue项目做微信分享总结
    js获取url参数
    vue微信支付遇到的坑
    Win7的环境变量下的系统变量path不小心修改了,怎么恢复
    解决ios上滑动不流畅及滚动条隐藏无效问题
    数组更新检测
    列表渲染
    条件渲染
    vue调试工具的安装
  • 原文地址:https://www.cnblogs.com/liuzhiyun/p/11477710.html
Copyright © 2011-2022 走看看