awk的应用

                    awk的应用

     awk是Linux文本处理三剑客之一,是一款强大的报告生成器,不同于sed和grep,它的侧重点是如何把文本信息更好的展示出来,常用与统计和格式化输出。awk相当于微型的shell,有着自己一套语法结构,例如:循环结构,数组,条件判断,函数,内置变量等功能。处理对象一般纯文本文件或纯文本信息。在开源界的awk是gawk(GNU)。在Linux中常使用的gawk,但是一般都称之为awk。


基本用法:

gawk [options] 'program' file[ file ...]

program  : PATTERN { ACTION STATEMENT }

    由语句组成,语句分隔符是;

ACTION: print, printf

                file[ file...]:待处理的输入文件,可以是一个也可以是多个

gawk执行命令时,是一行一行进行处理文件file[ file ...]的。读取一行后,根据指定的分隔符将每行进行分割存储在一个动态数组中,然后根据pattern进行匹配,匹配了则执行 action statement操作,不匹配则不执行action statement。处理完这一行后,接着读取下一行,再进行同样的流程,知道所有文件都读取完。

wKiom1VgNkLR5JbHAAFYPqR_VUQ882.jpg


一、option选项


可以使用两种形式:-POSIX one letter, --GNU-style long options。主要有:

-F fs,--field-separator fs

指明分隔符fs

-v var=val,--assign var=val

给变量赋值。可以赋值的变量在BEGIN中介绍

-f program-file,--file program-file

从program-file文件中读取执行程序代码,可以使用多个-f或--file读取多个程序代码文件

-W dump-variables[=file],--dump-variables[=file]

打印文件[file]中的全局变量列表,包括变量名,类型,最后的赋值。没有指明文件时则为当前工作目录的的awkvars.out文件。在定义了较多函数时可以用来有效避免在需要用本地变量时用了全局变量,如for循环中的i、j等。

二、program:pattern   { action statements }


     pattern表示在处理文件时对对取得的每一行做匹配,匹配到就用后面的action进行处理,为匹配到就不用后面的action处理。 pattern与action可以缺一个,但不能同时缺少。当pattern缺失时,默认是匹配每一行;当action缺失时,默认为 { print }。

     statement可以有多个,中间用分号分隔。


(一)Patterns有如下几种:


           BEGIN

           END

           /regular expression/

           relational expression

           pattern && pattern

           pattern || pattern

           pattern ? pattern : pattern   

           (pattern)   分组

           ! pattern   取反

           pattern1, pattern2


      (1)BEGIN/END: 特殊模式

             BEGIN 和END:BEGIN在文件输入前执行一遍,END是在文件读入后执行一遍。这两者后面都必须跟action。

      (2) relational expression:关系表达式,有真假之分,一般来说,其结果为非0或非空字符串时为“真”,否则,为“假”;

     (3) &&, ||, and !  :逻辑或,与,非

     (4)pattern1 ? pattern2 : pattern3 

              当pattern1为真时,用pattern2进行匹配,否则用pattern3进行匹配

      (3) ‘pattern1, pattern2’:范围匹配,‘line ranges’,可用sed或vim的地址定界法;startline, endline

      (4) /regular expression/:正则表达式

       .          匹配任意字符,包括换行符

       ^          行首定位符

       $          行尾定位符 

       [abc...]   匹配 abc....中任意一个 

       [^abc...]  不匹配 abc....中任意一个 

       r1|r2      匹配 r1 或 r2,任选一 

       r1r2       先匹配 r1,然后接着匹配 r2,也即必须连续匹配r1r2 

       r+         多次匹配r 

       r*         匹配任意次r 

       r?         匹配0次或1次r 

      (r)        分组 

      r{n}               精确匹配n次r

      r{n,}             至少匹配n次r

      r{n,m}     匹配n到m次r

      \y         词首或者词尾定位符 

      \B         词内匹配定位符(即不能是词首或词尾) 

      \<         词首定位符 

      \>         词尾定位符 

      \w         匹配文件名的组成字符 (字母、数字、下划线三者之一) 

      \W         匹配非文件名组成字符 

      [:alnum:]  字母数字字符 

      [:alpha:]  字母字符 

      [:blank:]  空白字符Space or tab characters. 

      [:cntrl:]  控制字符 

      [:digit:]  数字字符 

      [:graph:]  可视打印字符(不包括空格) 

      [:lower:]  小写字母字符 

      [:print:]  可打印非控制字符 

      [:space:]  空白字符 (包括 space, tab) 

      [:upper:]  大写字母字符 

      [:xdigit:] 十六进制字符


(二)action处理动作


    对前面pattern的匹配结果处理动作主要有两种:print和printf。


 The print Statement:


    print        打印输出当前行,结尾为换行符

    print expr-list       打印输出列表,列表之间可用空格或者逗号分隔,空格表示连续打印,逗号表示以OFS分隔(默认为空格,除非前面option中指定了) 

    print expr-list >file 将表达式列表输出至文件file 

    print ... >> file    将打印列表追加至文件file

    print ... | command   将打印列表通过管道送给下一个命令


 The printf Statement:  

  

    printf fmt, expr-list 将表达式列表格式化并输出打印至屏幕

    printf fmt, expr-list >file  将表达式列表格式化后输出至文件file

   (1) fmt,format,是必须的,表示格式化输出;

   (2) 不会自动换行,需显式给定行分隔符(\n);

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

  格式符format:都以%开头,后跟一个字符

     %c: 显示字符的ASCII码;

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

     %e, %E: 科学计数法显示数值;

     %f: 显示为浮点数;float

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

     %s: 字符串

     %u: 无符号的整数

     %%: 显示%自身

  修饰符:

     #[.#]: 第一个#指定显示宽度,例如%30s;第二个#表示小数点后的精度;

     -: 左对齐

     +:显示数值符号


(三)statement中可用的元素:


1、变量:


 (1)built-in variables内建变量:


      IGNORECASE   设成非0值时,忽略gawk命令中出现的字符串的字符大小写

      OFMT 数字的输出格式;默认值为%.6 g

      FS: input field seperator,输入字段分隔符,默认为空白字符;

              如果没有指明,且没有空格分隔,或者指明的分隔符航中不存在,则整行为一个字段

      RS:input record separator,输入行分隔符, 默认为换行符;

      OFS: output field seperator,输出字段分隔符,默认为空白字符;

      ORS:output record separator, 输出行分隔符,默认为换行符;

      NF: number of field in current record,当前行的字段数;

      NR:The total number of input records seen so far已处理的输入数据行数目,所有文件统一计数;

      FNR:The input record number  in  the  current  input file已处理的输入数据行数目,各文件分别计数;

      ARGC:命令行参数的个数;不包括program

      ARGV:数组,保存了命令行参数;

      ARGIND 当前文件在ARGV中的位置

      ENVIRON 当前shell环境变量及其值组成的关联数组

      FILENAME 用作gawk输入数据的数据文件的文件名


 (2) 自定义变量


      -v var=val: 

          变量名区分字符大小写

       定义变量的位置:

      (1) 可以program中定义变量,可以在{}中定义,定义后与其他body用分号隔开;

      (2) 通过-v选项定义变量;


2、String Constants字符串常量:只能在“”中起作用

        \\   左斜线 

        \b   删除 

        \n   换行 

        \t   水平tab键 

        \v   竖tab


3、operator操作符:


    算术操作符:

      x+y, x-y, x*y, x/y, x^y, x%y

      -x: 负值

      +x: 转换为数值

    字符串操作:字符串连接,即加个空格

    赋值操作符:

       =, +=, -=, *=,  /=,  %=, ^=

       ++, --

    比较操作符:

       >, >=, <. <=, ==, !=

    模式匹配符:

       ~

       !~

    例子:~]# awk -F: '{$3>=500?usertype="common user":usertype="sysuser or admin";printf "%20s:%-s\n",$1,usertype}' /etc/passwd


4、函数调用:


     function_name(argu1,argu2,...)


① String Functions字符串函数

       

      asort(s [, d]) 将数组s按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。如果指定了d,则排序后的数组回存储在数组d中

      asorti(s [, d]) 将数组s按索引值排序。生成的数组会将索引值作为数据元素值,用连续数组索引来表明排序顺序。如果指定了d,排序后的数组回存储在数组d中

      gensub(r, s, h [, t]) 查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果h是一个以g或者G开头的字符串,就用s替换掉匹配的文本。如果h是一个数字,它表示要替换掉第几处r匹配的地方

      gsub(r, s, [, t]) 查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果找到了,就全部替换成字符串s

      index(s, t) 返回字符串t在字符串s中的索引值,如果没找到的话,返回0

      length([s]) 返回字符串s的长度,如果没有指定的话,返回$0的长度

match(s, r [, a]) 返回字符串s中正则表达式r出现位置的索引。如果指定了数组a,它会存储s中匹配正则表达式的那部分

      split(s, a [, r]) 将s用FS字符或正则表达式r(如果指定了的话),分开放到数组a中。返回字段的总数

      sprintf(format, variables) 用提供的format和variables返回一个类似于printf输出的字符串

      sub(r, s [, t]) 在变量$0或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处匹配

      substr(s, i [, n]) 返回s中从索引值i开始的n个字符组成的子字符串。如果未提供n,则返回s剩下的部分

      tolower(s) 将s的所有字符转换成小写 

      toupper(s) 将s的所有字符转换成大写 


② Time Functions时间函数

      mktime(datespec) 将一个YYYY MM DD HH MM SS [DST]格式置顶的日期转换彻骨时间戳(时间戳指:自1970-01-01 00:00:00 UTC到现在,以秒为单位的计数,通常称epoch time)

      strftime(format [, timestamp]) 将当前时间的时间戳huotimestamp(如果提供了的话)转化成用shell函数格式date()的格式化日期

      systime() 返回当前时间的时间戳(同上面的时间戳)

③ USER-DEFINED FUNCTIONS自定义函数

     必须使用function关键字

     function name([variables])

     {

         statements

      }

     可以使用return语句返回值

     使用自定义函数定义函数时,必须在所有代码块之前,包括BEGIN

    #  gawk 'function test(v1){print v1} BEGIN{ test("abc") } ' 

    abc


5、Control Statements控制语句:


  控制语句有如下几种:

        if (condition) statement [ else statement ]

        while (condition) statement

        do statement while (condition)

        for (expr1; expr2; expr3) statement

        for (var in array) statement

        break

        continue

        delete array[index]

        delete array

        exit [ expression ]

       { statements }


 ①、if-else

    语法:if (condition) statement [ else statement ] 

    if (condition) { statements; } [ else { statements; }]

    # awk -F: '{if ($3>=500) print $1," is a common user." }' /etc/passwd

    # awk -F: '{if ($3>=500) {print $1," is a common user."} else {print $1," is a system user or admin."}}' /etc/passwd

    # awk '{if (NF>6) print NF, $0 }' /etc/inittab

    用法:对awk取得的整行或行中的字段做条件判断;

②、 while循环

   语法:while (condition) statement

         while (condition) { statements }

    条件为真时进入循环,直到为假退出;

    用法:通常用于在当前行的各字段间进行循环;

    # awk '{i=1;while(i<=NF){printf "%20s:%d\n",$i,length($i); i++}}' /etc/inittab

     # awk '{i=1;while(i<=NF){if (length($i)>5) {printf "%20s:%d\n",$i,length($i);} i++}}' /etc/inittab


③、 do-while循环

    语法:do statement while (condition)

          do { do-while-body }  while (condition)

     意义:至少执行一次循环体do-while-body再进入循环体;


④、 for循环

     语法: for (expr1; expr2; expr3) statement

            for (expr1; expr2; expr3) { statements }

            for (varaiable assignment; condition; iteration process) { for-body }

     # awk '{for(i=1;i<=NF;i++) {printf "%s:%d\n", $i, length($i)}}' /etc/inittab

     # awk '{for (i=1;i<=NF;i++) {if (length($i)>=5) {printf "%20s:%d\n",$i,length($i)}} }' /etc/inittab

     for循环在awk中有一个专用于遍历数组元素:

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


⑤、 switch:这个是gawk所特有的

      语法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}

      比如: switch ($3) {case xy :  ;case mn:  ; default:  }


⑥、 break and continue

      break [n]: 退出当前循环

      continue:提前结束本轮循环,直接进入下轮循环


⑦、 next

      提前结束对本行的处理而进入下一行的处理

     # awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd

6、Array关联数组:

       array[index-expression]

       index-expression: 

          可以使用任意字符串;

          如果某数组元素事先不存在,在引用时,awk会自动创建此元素并将其值初始化为空串;

          因此,若要判断数组是否存在某元素,要使用“index in array”进行;

      要遍历数组中的每个元素,使用: for (var in array) { for body }  

      注意:var会遍历array的每一个索引,print array[var]  

      例子:统计每一行中各单词分别出现的次数

      # awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]}}' awk.txt

      把每一个单词当作一个事先存在的索引的下标,当这个单词对应的元素的值是已经出现的次数,我们让awk去遍历这个字段在我们的下标索引中是否存在,存在就加1。表达式中,count[$i]是以单词作为索引的数组,没有赋值则为空,++后就为至少为1了,在遍历单词时,如果轮到这个单词又出现了,则会++,值加1,轮到出现新的单词时,则记为新数组索引,其值++。

     # ss -tan | awk '!/^State/{state[$1]++}END{for (i in state) {print i,state[i]}}'

     # netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}'

     统计httpd访问日志中,每个IP出现的次数;

     # awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log 


下面是操作截图:


wKiom1VgN9HSjrNkAAJ-h2tiJLk331.jpg

wKiom1VgN9vS9-RzAALQIp-Zsss453.jpg

wKioL1VgOWniKszfAAF27-b3j0w239.jpg

wKiom1VgN-Th8c3_AAFICjeHgSY020.jpg

wKiom1VgN-7gh0ogAAGjCz3JFcE334.jpg

wKioL1VgOYSzQ3S-AAJ0LofxQhM819.jpg

wKioL1VgOa3Q8mMCAAOtnZXbGQs463.jpg

wKioL1VgObaiTXriAAFTw7Qx-_0833.jpg

wKioL1VgOcmz8c8SAAIXDg_7CSU256.jpg

wKioL1VgOfKD8DnMAAJXZm7rz3U138.jpg

wKioL1VgOfiD2l_JAAGXCgolpDQ529.jpg

wKiom1VgOHTAN1JxAAECY_SiUtQ360.jpg


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章