模式扫描与处理语言--awk

写在前面:

    博客书写牢记5W1H法则:What,Why,When,Where,Who,How。

本篇主要内容:

● awk


简介:

   CentOS中所用的awk是指Gawk,即GNU AWK。是由Aho, Kernighan, and Weinberger三位开发的,是早起UNIX上awk的延伸。


awk工作模式:

   awk是由主循环脚本和循环体前后脚本三部分组成的。

   主循环:从文件第一行开始,对每一行进行处理操作,直到最后一行或用户手动终止(使用了exit命令)。

   循环前:在脚本前添加BEGIN关键字,将在主循环开始前完成脚本内容的执行;

   循环后:在脚本前添加END关键字,将在主循环结束后完成脚本内容的执行;

   补充:awk脚本允许在脚本的任意位置添加 # + 注释内容。


使用格式:

   awk [选项] 'PROGRAM' FILE ...

   PROGRAM:PATTERN{ACTION STATEMENTS}

      {}内多条语句用";"分隔


常用选项:

   -f Program-file

      --file Program-file

      指定脚本文件

   -F fs

       --field-separator fs

       指定域(列)分隔符,这里的分隔符可以是多个字符或PATTERN

   -v var=val

       --assign var=val

       声明自定义变量或为内建变量赋值;也可以直接在{}中定义

   -d[file]

       --dump-variables[=file]

       导出所有变量信息,省略file则使用缺省文件awkvars.out

内建变量:

   NF:number of fields,当前行域(列)的数量

   $0:当前行

   $1:第一列


   ARGC:arguments count.命令参数数量(包括awk本身以及后跟的文件)

   ARGV:arguments array,数组,其中的元素是各命令参数。索引为从0到ARGC-1

   ARGIND:the index in ARGV,当前awk正在处理的ARGV元素索引值。

   

   FILENAME:当前处理的文件名。等同于ARGV[ARGIND]


   FNR:number of input records by file,当前处理的行的行号,不同文件重新开始计数。

   NR:number of input records,当前处理的行的行号,不同文件继续上一文件计数。

例:

[root@www ~]# head -2 /etc/passwd > passwd_head
[root@www ~]# awk 'BEGIN{print ARGC}' passwd_head file
3
[root@www ~]# awk 'BEGIN{print ARGV[0]}' passwd_head file
awk
[root@www ~]# awk 'BEGIN{print ARGV[1]}' passwd_head file
passwd_head
[root@www ~]# awk 'BEGIN{print ARGV[2]}' passwd_head file
file
[root@www ~]# awk '{print FNR}' passwd_head file
1
2
1
2
3
4
[root@www ~]# awk '{print NR}' passwd_head file
1
2
3
4
5
6
[root@www ~]# awk '{print FILENAME}' passwd_head file
passwd_head
passwd_head
file
file
file
file
[root@www ~]# awk '{print ARGV[ARGIND]}' passwd_head file
passwd_head
passwd_head
file
file
file
file


   行分隔:

      FS:input field sepatator,输入分隔符,可以是多个字符或PATTERN

         如:FS="[[:space:]]+|:" 指定分隔符为多个空格或":"

      OFS:output field seprator,输出分隔符

      RS:input record separator,输入换行符

      ORS:output record separator,输出换行符

      FIELDWIDTHS:使用固定长度字符取每一列,而不再使用FS,使用空格分隔多个列宽

      FPAT:fields pattern,指定匹配模式切割列,即能匹配到模式则当做一列

例:

[root@www ~]# cat file
"01","1008","0","10080539"
"01","1013","X","10080539"
"03","1007","0","20110625"
"03","1076","X","20110625"
[root@www ~]# awk 'BEGIN{FS="[\",]"}{print $2,$5}' file
01 1008
01 1013
03 1007
03 1076
[root@www ~]# awk 'BEGIN{FIELDWIDTHS="1 2 3 4 3 1 3 8 1"}{print $2,$4}' file
01 1008
01 1013
03 1007
03 1076
[root@www ~]# awk 'BEGIN{FPAT="[0-9X]+"}{print $1,$2}' file
1008
1013
1007
1076


数组:

   数组赋值:

      ARR[INDEX]="" 支持关联数组

   数组取值:

      取数组所有元素

         for(INDEX in ARR) print ARR[INDEX]

      判断是否存在索引的值"VALUE"

         if(VALUE in ARR) print "OK"


ACTION:

   print

      print [item1,item2,...]

      输出的变量不用加"$";

      省略item则相当于print $0

   printf

      printf FORMAT,item1,item2,...

      不会自动换行,可使用\n手动换行

      FORMAT中需要分别指定每个item的格式占位符

      格式占位符:

         %s:显示字符串;

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

         %f:显示为浮点数;

         %c: 显示字符的ASCII码;

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

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

         %u:无符号整数;

         %%: 显示%自身;

      修饰符:

         m[.n]:m为数字,控制显示的宽度;n为数字,表示小数点后的精度;

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

         +:显示数字符号(即便是正数也要显示+)

例:

[root@www ~]# awk -F: '{printf "UserName:%s  UID:%s\n",$1,$3}' passwd_head 
UserName:root  UID:0
UserName:bin  UID:1
[root@www ~]# awk -F: '{printf "UserName:%-4s  UID:%s\n",$1,$3}' passwd_head 
UserName:root  UID:0
UserName:bin   UID:1


操作符:

   算数运算:

      + - * / % ^ (幂运算)

      -x (取负)

      +x (转换为数值)

   赋值:

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

      ++ --

   比较操作符:

      > >= < <= != ==

   模式匹配:

      ~:VAR~PATTERN PATTERN能匹配到VAR中的字符串

      !~:VAR!~PATTERN

   函数调用:

      function_name(arg1,arg2,...)

   条件表达式:

      selector?if-true-expression:if-false-expression

例:

  #算数运算
[root@www ~]# awk 'BEGIN{i=1;j=2;i++;print i+j}'
4
  #注意模式匹配格式/PATTERN/
[root@www ~]# echo "I am your apple." | awk '{$0~/apple/?yn="OK":yn="NO";print yn}'
OK
[root@www ~]# echo "I am your orage." | awk '{$0~/apple/?yn="OK":yn="NO";print yn}'
NO
  #判断uid是否大于等于1000,大于等于1000则输出“用户名 is Login User”,否则输出“用户名 is System User”
[root@www ~]# awk -F: '{$3>=100?usertype="is Login User":usertype="is System User";print $1,usertype}' /etc/passwd


PATTERN:

    BEGIN

    END

    BEGINFILE

    ENDFILE

    /regular expression/ :正则表达式

    relational expression :关系表达式,为真则后续操作执行,如==等

    pattern && pattern

    pattern || pattern

    pattern ? pattern : pattern

    (pattern)

    ! pattern

    pattern1, pattern2

       范围匹配,从匹配pattern1的行开始,到pattern2的行结束

例:

  #输出文件的4-9行
[root@www ~]# cat -n /etc/passwd | awk '4<=NR && NR<=9{print $0}'
[root@www ~]# cat -n /etc/passwd | awk '$1==4,$1==9{print $0}'


控制语句:

   if (condition) statement [ else statement ]

    while (condition) statement

    do statement while (condition)

       与while循环不同的是,至少循环一次

    for (expr1; expr2; expr3) statement

    for (var in array) statement

    break

    continue

    delete array[index]

    delete array

    exit [ expression ]

    { statements }


    switch (expression) {

    case value|regex : statement

    ...

    [ default: statement ]

    }

例:

  #使用if语句,输出默认shell为/bin/bash的用户信息

[root@www ~]# cat awk_program 
{
FS=":";
if($NF=="/bin/bash")
print $0
}
[root@www ~]# awk -f awk_program /etc/passwd
fred:x:1002:1002::/home/fred:/bin/bash
storm:x:1003:1003::/home/storm:/bin/bash
hadoop:x:1004:1004::/home/hadoop:/bin/bash
archlinux:x:1005:1005::/users/archlinux:/bin/bash
gentoo:x:3002:3002::/home/gentoo:/bin/bash


  #使用awk显示磁盘使用率大于等于20%的磁盘信息

[root@www ~]# df -h | awk -F '[[:space:]]+|%' '/^\/dev/ {if($5>=20) print $0}'
/dev/sda3        20G   14G  6.8G  67% /usr
/dev/sda1       497M  191M  307M  39% /boot
[root@www ~]# df -h | awk '/^\/dev/ {FS="[[:space:]]+|%";if($5>=20) print $0}'
/dev/sda3        20G   14G  6.8G  67% /usr
/dev/sda1       497M  191M  307M  39% /boot


  #输出/etc/passwd文件,每10行添加一个页码

[root@www ~]# awk '{print $0}{if(NR%10==0)print "--",NR/10,"--------"}' /etc/passwd


  #使用awk获取/etc/passwd文件的第一行,列出每个字段的字符数量

[root@www ~]# awk -F: 'NR==1{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/passwd
root 4
x 1
0 1
0 1
 0
/root 5
/bin/bash 9


  #利用awk统计本机所有连接状态的连接数量

[root@www ~]# netstat -tan | awk '/^tcp\>/{stat[$6]++}END{for(s in stat) print s,stat[s]}'
LISTEN 5
ESTABLISHED 2


  #利用awk统计所有访问本机http服务的主机IP,并统计访问次数(提示,所有成功的访问都会被记录在/var/log/httpd/access_log文件中)

[root@www ~]# awk '{ips[$1]++}END{for(i in ips)print i,ips[i]}' /var/log/httpd/access_log 
172.18.31.1 45
172.18.31.6 1
172.18.31.7 2


  #利用awk统计本机中开机挂载的所有文件系统类型及数量

[root@www ~]# awk '/^UUID/{fstype[$3]++;}END{for(t in fstype)print t,fstype[t]}' /etc/fstab 
xfs 3


  #使用awk统计一篇文章中的前10个高频字

[root@www ~]# awk -F ''  '{for(i=1;i<=NF;i++)word[$i]++}END{for(w in word) print w,word[w]}' c_1118548704.htm | sort -rnk2 | head 
, 74
党 54
学 40
、 39
要 35
习 28
。 28
育 27
的 27
教 27


I/O控制

   next

      进入下一行的循环

   nextfile

      结束当前文件操作,从下一文件读取行并操作

例:

  #输出uid为偶数的用户信息

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


内置函数:

   int():截出数字

   rand():随机数,0<=N<1

   length([s]):获取字符串长度,如果s未给出,则获取$0的字符串长度

   字符串处理:

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

      gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容;


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

例:

  #使用awk获取正在访问本机的IP并统计每个IP的连接数

[root@www ~]# netstat -tanp | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count)print i,count[i]}'
172.18.31.1 2
0.0.0.0 5



你可能感兴趣的:(awk,工具,文本处理)