一、AWK介绍

   Linux文本处理工具三剑客:grep、sed和AWK。其中grep是一种文本过滤工具,sed是文本行编辑器,而AWK是一种报表生成器,就是对文件进行格式化处理,这里的格式化不是文件系统的格式化,而是对文件内容进行各种“排版”,进而格式化显示
   在Linux之上我们使用的GUN awk ,简称gawk,并且gawk其实awk的链接文件,因此在系统上使用awk和gawk都是一样的。我们通过mangawk可以获得gawk的相关功能说明----------- gawk-pattern scanning and processing language(模式扫描及各种处理语言),gawk是一种过程式编程语言,gawk还支持条件判断,数组、循环等各种编程语言中所有可以使用的功能,因此我们还可以吧gawk称为一种监本语言解释器。

二、AWK基本用法

   awk 在处理文本时也是一次读取一行文本,文件的每一行称为记录,由分隔符分隔的字段(域)标记为$1,$2...$n,称为域标识,$0为所有域,和shell中变量$符含义不同,然后根据输入分隔符(默认为空格字符)进行切片,切成n段,然后将每一片都赋予awk内部的一个变量当中这些$1,$2等等一直到最后一个,awk就可以对这些片段进行处理,比如某一段、特定段,比如计数、运算等

 1、awk的运行方式有3种

  1)awk命令行

   #awk

  2)awk 程序文件

   # awk -f /PATH/AWK_SCRIPT

  3)awk脚本

   #!/bin/awk -f

2、awk的基本用法

  awk [option] ‘program’ file1 file2
   Option:选项
    -F[] :指明输入时用到的字段分隔符,例:-F:
    -v var=value: 自定义变量,例:-v var=123
    -f /PATH/AWK_SCRIPT:指定awk程序的文件
   Program:prattern{action statements;}
    awk编程语言,通常由BEGIN语句块、能够使用模式匹配的通用语句块、END,共3部分组成。Program通常是被单引号或双引号中
    parttern部分决定动作语句何时触发及触发事件
      BEGIN:在读取文件之前执行
      END:在读取文件之后执行
    Action statements:动作语句,可以是由多个语句组成,各语句之间使用分号分隔“;”
      print:换行打印
      printf:不换行打印

 3、 Awk工作原理

  第一步:执行BEGIN{action;… }语句块中的语句
  第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这 个过程,直到文件全部被读取完毕。
  第三步:当读至输入流末尾时,执行END{action;…}语句块
   BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个 可选的语句块,比如变量初始化、打印输出表格的表头等语句通常 可以写在BEGIN语句块中
   END语句块在awk从输入流中读取完所有的行之后即被执行,比如 打印所有行的分析结果这类信息汇总都是在END语句块中完成,它 也是一个可选语句块
   pattern语句块中的通用命令是最重要的部分,也是可选的。如果 没有提供pattern语句块,则默认执行{ print },即打印每一个读取 到的行,awk读取的每一行都会执行该语句块

三、AWK变量

  变量:内置变量和自定义变量

 1、内置变量

  FS:输入字段分隔符,默认为空白字符
   awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd
   awk –F: '{print $1,$3,$7}’ /etc/passwd
  OFS:输出字段分隔符,默认为空白字符
   awk -v FS=‘:’ -v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd
   RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效
   awk -v RS=' ' ‘{print }’ /etc/passwd
   ORS:输出时的行分隔符,默认为换行符
   awk -v RS=' ' -v ORS='###'‘{print }’ /etc/passwd
   NF:字段数量,当前行的字段数
   awk -F: ‘{print NF}’ /etc/fstab,显示当前行的字段数
   awk -F: '{print $(NF-1)}' /etc/passwd 显示当前行的第NF个字段
   NR:显示行数;命令后跟的所有文件将统一合并计数
   awk '{print NR}' /etc/fstab
   awk END'{print NR}' /etc/fstab
   FNR:显示行号;各文件分别计数,行号
   awk '{print FNR}' /etc/fstab /etc/inittab
  FILENAME:显示当前文件名
   awk '{print FILENAME}’ /etc/fstab
   ARGC:命令行参数的个数
   awk '{print ARGC}’ /etc/fstab /etc/inittab
   awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
   ARGV:数组,保存的是命令行所给定的各参数
   awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
   awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab
  注意:当引用这些内置变量时,不用加$;使用ARGC和ARGV时,后面可以是文件名,也可以是a b c d 任意值,不管是文件名或是任意字符串,以空格相隔,每一个值都会被赋值给ARGC这个数组的不同下标,默认从0开始,awk也是一个参数,awk是固定的被赋值给了ARGV[0],后面的所有参数按顺序分配给各个下标,
  例:1.这个命令即是打印出这个参数的个数,加上awk本身总共5个
AWK的使用
    2.显示各个参数的值
AWK的使用

 2、自定义变量

  自定义变量是区分字符大小写的,自定义变量有两种方法:

  1)-v var=value

  2)在program中直接定义

  例: awk -v test='hello gawk' '{print test}' /etc/fstab
    awk -v test='hello gawk' 'BEGIN{print test}'
    awk 'BEGIN{test="hello,gawk";print test}'
    awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd
  用-v选项和在program中定义的变量的区别,使用-v定义的变量,只有第一次执行的时候会读取一次,在后面的program中弱势变量值发生变化,便不可再回到初值,而program中的命令是每读取一行的时候就会被执行一次,所以,当每读取完一行的时候都会再次被赋值为最初的那个值,所以可以根据自己的需求来选择怎么定义变量,在调用这些变量的值的时候不需要加$,所以如果要输出一些字符串的时候,需要用上引号引起来,否则系统则会认为是要调用变量名为这串字符串的变量的值,

四、Print与printf

 1、print的格式

  print格式 print item1,item2...

  1)各intem之间逗号分隔符时,输出各item以一个空格分隔

  2)输出的各item可以是字符串,也可以是数值;当前记录的字段、变量或awk的表达式

  3)如省略item,相当于print $0

  4)输出空白字符:print “ “

   示例:

   awk '{print "hello world"}' 显示字符串hello world
   awk -F: '{print}' /etc/passwd 显示/etc/passwd文件中的所有内容
   awk -F: '{print "wang"}' /etc/passwd 每读取/etc/passwd文件中一行内容输出一次字符串“wang”
   awk -F: '{print $1}' /etc/passwd 每读取一行,就截取以“:”为分隔符的第一个字段
   awk -F: '{print $0}' /etc/passwd 显示/etc/passwd文件中每一行以“:”分隔的所有字段(等同于awk -F: '{print}' /etc/passwd)
   awk -F: '{print$1"\t"$3}' /etc/passwd 输出/etc/passwd每行第1和第3字段,中间以tab分隔
   tail -3 /etc/fatab |awk’{print $1,$4}’ 显示/etc/fstab中最后3行的第1字段和第4字段

 2、printf格式化输出

  printf “FORMAT” ,item1,item2...

   1)必须指定FORMAT(输出格式符)

  2)不会自动换行,需要显式给出换行控制符,\n,换行符必须放在FORMAT中才管用,跟在item后面是不对的

  3)FORMAT中需要为后面每个item指定输出格式符,否则item无法显式,各item之间以逗号分隔

  输出格式符(FORMAT):与item一一对应
   %c: 显示字符的ASCII码
   %d, %i: 显示十进制整数
   %e, %E:显示科学计数法数值
   %f:显示为浮点数
   %g, %G:以科学计数法或浮点形式显示数值
   %s:显示字符串
   %u:无符号整数
   %%: 显示%自身
  修饰符:每一种格式符都有一些修饰符
   #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
   -: 左对齐(默认右对齐) %-15s
   +:显示数值的正负符号 %+d
  示例:
   awk -F: ‘{printf "%s",$1}’ /etc/passwd
   awk -F: ‘{printf "%s\n",$1}’ /etc/passwd
   awk -F: ‘{printf "%-20s %10d\n",$1,$3}' /etc/passwd
   awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd
   awk -F: ‘{printf “Username: %s,UID:%d\n",$1,$3}’ /etc/passwd
   awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’ /etc/passwd
   awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd

五、AWK操作符

  算数操作符:
   x+y:加;
   x-y:减;
   x*y:乘;
   x/y:除;
   x^y:次方;
   x%y:取余;x除以y得出的余数
   -x:转换为负值,
   +x转换为数值
  字符串操作符:没有符号的操作符,字符串连接
  赋值操作符:
   =:等于;
   +=:自加;例,x+=y,意思是把x本身的值加上y的值再赋给x
   -=: 自减;例,x-=y,意思是把x减去y的值再赋值给x
   *=: 自乘;例,x*=y,意思是把x乘以y的值再赋值给x
   /=: 自除;例,x/=y,意思是把x除以y的值再赋值给x
   %=:取余赋值;例,x%=y,意思是x除以y后的余数赋值给x
   ^=: 次方;例,x^=y,意思是把x的y次方的值再赋值给x
   ++:递加;例,i++,意思是把i的值加1再赋值给i,等同于i+=1
   - -: 递减;例,i- -,意思是把i的值减1再赋值给i,等同于i-=1
  比较操作符:
   = =: 等于
   !=: 不等于
   \>: 大于
   \>=: 大于等于
   <: 小于
   <= : 小于等于
  模式匹配符:
    ~:左边是否匹配包含右边
    !~: 是否左边和右边是否不匹配包含
  逻辑操作符:与&&;或||;非!
  示例:
   awk –F: '$0 ~ /root/{print $1}‘ /etc/passwd
   awk '$0~“^root"' /etc/passwd
   awk '$0 !~ /root/‘ /etc/passwd
   awk –F: ‘$3==0’ /etc/passwd
   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
  函数调用:function_name(argu1,argu2...)
  条件表达式(三目表达式):
   格式: selector?if-true-expression:if-false-expression
  三目表达式顾名思义就是有三个表达式组成的,问号之前的表达式通常为判断表达式,问号之后的表达式是满足条件才会执行的语句,冒号之后的是当不满足条件时才会执行的语句。
示例:
  awk -F: '{$3>=1000?usertype="common user":usertype="sysadmin or sysuser";printf "%15s: %-s\n" ,$1,usertype}' /etc/passwd

六、AWK条件判断

  PATTERN:根据pattern条件,过滤匹配的行,再做处理

 1、如果为指定:空模式,匹配每一行

 2、/regular expression/:仅处理能够模式匹配到的行,需要用//括起来,//之间可以是字符串,也可以是正则表达式模糊匹配。

   awk '/^UUID/{print $1}' /etc/fstab
   awk '!/^UUID/{print $1}' /etc/fstab

 3、Relational expression:关系表达式,结果为真才会被处理

  真:结果为非0值,非空字符串
  假:结果为空字符串或0值
示例:
  awk -F: 'i=1;j=1{print i,j}' /etc/passwd
  awk ‘!0’ /etc/passwd
  awk ‘!1’ /etc/passwd
  awk –F: '$3\>=1000{print $1,$3}' /etc/passwd
  awk -F: '$3\<1000{print $1,$3}' /etc/passwd

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

 4、Line ranges:行范围

  Startline,endline:/pat1/,/pat2/不支持直接给出数字格式
  示例:
   awk -F: '/^\<root\>./,/^\<nobody\>./{print $0}' /etc/passwd
   awk -F: '/^\<root\>/,/^\<nobody\>/{print $0}' /etc/passwd
   awk -F: '(NR>=10&&NR<=20){print NR,$1}' /etc/passwd

 5、BEGIN/END模式

  BEGIN{}:仅在开始处理文件中的文本之前执行一次
  END{}:仅在文本处理完成之后执行一次

 6、示例:

  awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3} END{print "end file"}' /etc/passwd
  awk -F : '{print "USER USERID“;print $1":"$3} END{print "end file"}' /etc/passwd
  awk -F: 'BEGIN{print " USER UID \n--------------- "}{print $1,$3}' /etc/passwd
  awk -F: 'BEGIN{print " USER UID \n--------------- "}{print $1,$3}'END{print "=============="} /etc/passwd
  seq 10 |awk ‘i=0’ 不显示所有行
  seq 10 |awk ‘i=1’ 显示所有行
  seq 10 | awk 'i=!i‘ 显示基数行
  seq 10 |awk -v i=1 '!(i=!i)' 显示基数行
  seq 10 | awk '{i=!i;print i}‘每执行一行,显示一次i的真假值
  seq 10 | awk ‘!(i=!i)’ 显示偶数行
  seq 10 |awk -v i=1 'i=!i' 显示偶数行

七、AWK action

 1、常用的action分类

  1)expressions:算数,比较表达式

  2)Control statements:if,while等

  3)Compound statements:组合语句

  4)Input :输入语句

  5)Output statements:输出语句print等

 2、Awk控制语句if-else

  语法:if(condition){statement1}[else{statement2}]
     If(condition1){statement}else if(condition2){statement2}else{statement3}
  这种语法看着跟shell中的if--else语句相差无几,第一种格式是单if语句,执行机制是先判断条件(condition)部分,值为则true执行statement1部分语句,值为false则执行statement2部分的语句;第二种是多if语句,有多个条件多个语句,先判断第一个条件(condition1),值为true执行statement1部分的语句,值为false就判断下一个条件condition2,值为true就执行statement2,值为false就执行else后面的statement3语句;
  使用场景:对awk取得的整行或某个字段做条件判断
   示例:
   awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
   awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
   awk '{if(NF\>5) print $0}' /etc/fstab
   awk -F: '{if($3\>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
   awk -F: '{if($3\>=1000) printf "Common user: %s\n",$1; else printf "root or Sysuser: %s\n",$1}' /etc/passwd
   df -h|awk -F% '/^\/dev/{print $1}'|awk '$NF\>=80{print $1,$5}‘
   awk 'BEGIN{ test=100;if(test\>90){print "very good"} else if(test\>60){ print "good"}else{print "no pass"}}'

 3、Awk循环语句while

  语法:while(condition){statement;...}
  执行机制:先判断再执行,条件真,进入循环;条件假退出循环,statement部分可以有多个语句,组合语句,在statement处应该有一条是条件判断的值发生变化的语句,否则容易进入死循环
  使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用
  示例:
   awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
   awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10) {print $i,length($i)}; i++}}' /etc/grub2.cfg

 4、Awk循环语句do-while

  语法:do{statement;}while(condition)
  执行机制:先执行再判断,先执行一遍statement,再判断condition,如果条件为真则进入下一轮循环,如果为假就退出,无论真假,至少执行一次循环体
  示例:
   awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}‘
思考:下面两语句有何不同?
   awk ‘BEGIN{i=0;print ++i,i}’
   awk ‘BEGIN{i=0;print i++,i}’
AWK的使用
  前者输出的++i是先给i加1在输出,后者是先输出i再给i加值

 5、Awk循环语句for

  语法:for (expr1;expr2;expr3){statement;...}
  常见用法:for(var assignment;condition;iteration process){for-body}
  执行机制:variable assignment(变量的初始值),condition(条件),iteration process(步长,也就是没执行一次循环体后,使变量的值发生变化的语句);for-body(循环体),先赋初值变量(variable),再判断变量的值是否符合条件(condition),符合就执行循环体部分(for-body),然后再给变量加上步长(iteration process),再判断条件,为真时执行循环体部分,为假退出循环......
  特殊用法:for(var in array) {for-body}
  执行机制:给var多个值,一次使用一个值,执行一次循环,有多少个值就执行多少次循环,直到把array的所有的值都用完,array代表一个数组。
  示例:
   awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg

 6、性能比较

  性能比较就是,看某个命令从执行到出结果时的时长,哪个时间最短就说明哪个命令性能更好,这个查看性能的命令就是time,在命令的前面写入time,把要执行的命令用小括号括起来,再执行此命令,就会在显示执行结果的后面显示出时间
  例:
  time(awk'BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}')
  time(total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
  time(for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
  time(seq –s ”+” 10000|bc)

 7、Awk控制语句switch

  语法:switch(expression) {case VALUE1 or /REGEXP1/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
  执行机制:这个就相当于shell中的case语句,espression是一个表达式,当VALUE1的值满足REGEXP1的时候执行statement1,当VALUE2的值满足REGEXP2的时候,执行statement2语句,...当前面的所有条件都不满足的时候,执行default后面的statement n语句。

 8、Awk控制语句break和continue

  这两个语句的用法continue是提前结束当前这一轮循环,进入下一循环,break是结束当前的循环语句用于在for,while语句中
  示例:
   awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i%2==0)continue;sum+=i}print sum}‘
   awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i==66)break;sum+=i}print sum}

 9、Awk控制语句Next

  由于awk是逐行进行处理的,一行一行的处理,直到所有的行都被处理完结束,也相当于一个循环,next语句就相当于for、while循环语句的continue语句,用来结束对本行的处理而直接进入下一行处理。
  示例:
   awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd

八、AWK数组

  关联数组array[index-expression]
  Index-expression(下标):
   1)下标可以使用任意字符串;字符串要使用双引号括起来,例:weekdays[“mon”]="Monday“
   2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串
   3)若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
   4)若要遍历数组中的每个元素,需使用for循环
   5)格式:for(var in array) {for-body} var会遍历array的每个索引

  示例:
   awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"] ="Tuesday";for(i in weekdays) {print weekdays[i]}}‘
   netstat -tan | awk '/^tcp/{state[$NF]++}END {for(i in state) { print i,state[i]}}'
   awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
  例图:
AWK的使用
  使用awk查看一个文件中的每一行的重复次数
AWK的使用

九、AWK函数

  函数分为系统函数和自定义函数,

 1、系统函数

  数值处理:
   rand():返回0和1之间一个随机数;使用这个函数之前必须先写一个srand()语句,才能产生随机0到1之间的小数,保留6位,如下图:
AWK的使用
AWK的使用
  示例:产生10个0到100的随机整数
AWK的使用
  字符串处理:
   length([s]):返回指定字符串的长度,并且在这种模式下,不管是字母数字还是汉字,都是一个占用一个字符
AWK的使用
   sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹 配的内容替换为s
AWK的使用
   gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换 为s所表示的内容
AWK的使用
   split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存 至array所表示的数组中,第一个索引值为1,第二个索引值为2,…
  例图:
AWK的使用

 2、自定义函数

  格式:
    function name ( parameter, parameter, ... ) {
     statements
     return expression
    }
  执行机制:把函数编辑在一个文件中,name是函数的名字,parameter是虚参,调用函数的括号内的实参,每一个实参对应着一个虚参,在函数中虚参是调用实参的值来执行statement部分的表达式,return的作用类似shell中的echo,是打印结果在终端上,expression可以是变量名或者是表达式,
  示例:编辑文件abc,写一个函数,要求取最大值,
AWK的使用

十、调用系统命令

  格式:system(“cmd”)

 1、使用system时调用新系统命令的执行结果时,系统命令要用双引号引起来,否则不会显示任何结果,如下图:

AWK的使用

 2、空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用双引号引起来。如下图:

AWK的使用