【转】awk 详解

转自:http://blog.sina.com.cn/s/blog_a05fe43b0101qt09.html

.  AWK 说明

    awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。

             awk处理文本和数据的方式:它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。

             awk是一门语言:作用是做报表,日志分析等等。读取的时候是一次一行读取文件的。

二. awk命令格式和选项

    2.1. awk的语法有两种形式

           awk [options] 'command' filename

           awk [options] -f scriptfile var=value filename

    2.2. 命令选项

    (1)-F fs or --field-separator fs :指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。

    (2)-v var=value  从shell脚本传递变量到awk脚本或者命令中

    (3)-f scripfile or --file scriptfile :从脚本文件中读取awk命令

三、变量

    3.1.内置变量

内置变量      描述
$n            当前记录的第n个字段,字段间由FS分隔。★
$0            完整的输入记录。★
FS            字段分隔符(默认是任何空格)。★
NF            当前记录中的字段数。★
NR            当前记录数。★
OFS           输出字段分隔符(默认值是一个空格)。★
ARGC          命令行参数的数目。
ARGIND        命令行中当前文件的位置(从0开始算)。
ARGV          包含命令行参数的数组。
CONVFMT       数字转换格式(默认值为%.6g)
ENVIRON       环境变量关联数组。
ERRNO         最后一个系统错误的描述。
FIELDWIDTHS   字段宽度列表(用空格键分隔)。
FILENAME      当前文件名。
FNR           同NR,但相对于当前文件。
IGNORECASE    如果为真,则进行忽略大小写的匹配。
OFMT          数字的输出格式(默认值是%.6g)。
ORS           输出记录分隔符(默认值是一个换行符)。
RLENGTH       由match函数所匹配的字符串的长度。
RS            记录分隔符(默认是一个换行符)。
RSTART        由match函数所匹配的字符串的第一个位置。
SUBSEP        数组下标分隔符(默认值是\034)。

    3.2.用户自定义变量

       在awk中变量无须定义即可使用,变量在赋值时即已经完成了定义。变量的类型可以是数字、字符串。

      根据使用的不同,未初始化变量的值为0或空白字符串" ",这主要取决于变量应用的上下文。

    例子一、

     awk '$1 ~ /lg/ {mem = $2 * $3; print mem}' filename

    例子二、

     awk '$1 ~ /huang/ {name=$1; print name}' filename

    3.3. 数组

     awk数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。

     值和关键字都存储在内部的一张针对key/value应用hash的表格里。

     数组初始化(定义):

      arr[1]=1

      arr[2]=5

      str_arr["a"]="test"

      str_arr["b"]="test1"

     例如一、

awk 'BEGIN{str_tmp="it is a test";split(str_tmp,str_arr," ");for(k in str_arr){print k,str_arr[k];}}'

       #split是awk一个内置函数split(str_tmp,str_arr," ")操作之后会把 str_tmp变量按照空格分隔存储在数组str_arr中

       #注意:splite截取的数组下标从1开始。

四、运算符

    运算符                        描述

    = += -= *= /= %= ^= **        赋值

    ?:                            C条件表达式

    ||                            逻辑或

    &&                            逻辑与

    ~                             匹配正则表达式

    !~                            匹配正则表达式

    < <= > >= != ==               关系运算符

    空格                          连接

    + -                           加,减

    * / &                         乘,除与求余

    + - !                         一元加,减和逻辑非

    ^ ***                         求幂

    ++ --                         增加或减少,作为前缀或后缀

    $                             字段引用

    例子:

     例一、匹配操作符(~)    

awk '$1 ~/^root/' test将显示test文件第一列中以root开头的行。
awk '$1 !~/^root/' test将显示test文件第一列中不以root开头的行。

     例二、比较表达式  

awk 'BEGIN{num= 2>3? 2:3;print num}' #练习?:符合比较大小同时赋值
awk '$1 + $2 < 100' test。如果第一和第二个域相加大于100,则打印这些行。

记录和域

    1. 记录

           awk把每一个以换行符结束的行称为一个记录。

           $0变量:它指的是整条记录。

           变量NR:一个计数器,每处理完一条记录,NR的值就增加1。

           例如:      

awk '{print NR,$0}' test.txt  #将输出test.txt文件中所有行号和内容

    2. 域分隔符

  • 输入分隔符:当文件记录输入一行时候,默认是空格或tab为分隔,把这行分隔成一列一列。
    • 那么tab和空格就是分隔符,内建变量FS保存输入域分隔符的值。
    • 可以通过-F选项自定义修改FS的值。 
    • 可以同时使用多个域分隔符,这时应该把分隔符写成放到方括号中。
  •  输出分隔符:输出域的分隔符默认是一个空格,保存在OFS内建变量中。

    例子:       

awk -F: '{print $2,$4}' test.txt #将打印以冒号为分隔符的第二,第四列的内容。
awk -F'[:\t]' '{print $1,$3}' test.txt,表示以空格、冒号和tab作为分隔符。
awk -F: '{print $1,$5}' test.txt      #$1和$5间的逗号就是OFS的值。
awk 'BEGIN { OFS="%"} {print $1,$2}' test.txt 通过设置输出分隔符(OFS="%")修改输出格式。

    3. 域

        记录中每个以分隔符分隔的间隔中的内容称做“域”,默认情况下以空格或tab分隔。

        awk可跟踪域的个数,并在内建变量NF中保存该值。

     例子:    

awk '{print $3,$5}' test.txt  #将打印test.txt文件中第三和第五个以空格分开的列(域)。

 六、内置函数

     内置函数主要是处理字符串(文本)函数:

delete arr[1] 删除数组中的下标为1的元素.
length(string) 字符串长度。
index(string1,"abc") 查询字符串string1中"abc"是第几个。从一开始数。
tolower(mystring) 字符串转换为小写
toupper(mystring) 字符串转换为大写
substr(mystring,start,length) #截取字符串mystring中从start开始,length长度。
match(mystring,/[0-9]/) 

#正则匹配字符串,其中匹配完后结果会存储在内置变量RSTART     

#说明:/root/匹配的正则。RSTART 包含返回值(第一个匹配的位置)

     替换:

      sub(regex,regexstring,mystring)是把mystring中的包含regex的字符串替换为regexstring

      切分:

       split(mystring,存储,以什么分割)

       nums=split("a,b,c,sdfd,se",myeles,",");    #nums是数组中元素个数。

    例子:

      1.match练习

 [lg@master ~]$ awk '{match($0,/Tom/);print RLENGTH,RSTART}' test.txt
 3 9
 -1 0
 -1 0
[lg@master ~]$ cat test.txt
To 1000 Tom 89 Tom
lg      2000
lg      2000 te          

     2.tolower和toupper   

awk '{str=tolower($0);print str}' test.txt
awk '{str=toupper($0);print str}' test.txt

     3.length(string)

awk '{len=length($0);print len}' test.txt

     4.index(string1,"abc")

awk '{num=index($0,"Tom");print num}' test.txt

     5.substr(mystring,start,length);

awk '{str=substr($0,1,2);print str}' test.txt 

七、awk中调用shell命令

     1. 使用system函数system("cmd")

 awk 'BEGIN{ while( system("ls -l") | getline line ){ print line } }'

      2."cmd"调用

awk 'BEGIN{ "date +%Y%m%d-%H" | getline date; print date; }'

awk 'BEGIN{ while(("ls"|getline line)>0)  print line; }'

      3.交互是输入

awk 'BEGIN{ getline; print $0 }'

八、编程脚本

     编程脚本分三部分。BEGIN区  正文区  END区(三个部分可以有可以没有)

             完整写法:

             BEGIN{ 

             }

             {       

             }

             END{

             }

      说明:BEGIN 和END都执行一次,BEGIN是开始时候执行一次,END是结束读取时候执行那个一次。

      正文区是一直读取,执行。

      使用文件:-f

      举例子

              myawk.awk

               BEGIN{

                       print "start...."

                       FS=":"

               }

               {

                       print "username:" $1 "uid:" $3

               }

               END{

                       print "end...."

               }

             使用时候:

              awk -f myawk.awk /etc/passwd

九、编程语句

    1. if条件语句(说明其中的if就和c语言一样,不用之间有空格)

             if($2~/root/) {

                       print $1

             } else if($3=="adf"){

                       print "sdf"

             } else {

                       print $4

             }

       awk '!/root/ {print}' filename是不含root的使用脚本如下:

       if($0!~/root/) {

             print $2

       }

    2. for循环语句:

      for(i=0;i<4; i++) {

             print i

      }

    3. while循环语句:

      while($1=="sdf"){

             i++

      }

      do{

             i++

      }while(i<4)

    4.控制语句:

      exit(1) 整个程序退出。

      break  整个循环语句退出

      continue  跳过continue以下的语句,循环直接换回上边继续循环。

十、实战例子

    1.查看系统ip地址,只需要ip地址

 ifconfig|egrep "inet addr"|awk '{print $2}'|awk -F ":" '{print $2}'

    2、统计apache日志单ip连接数排名(这个常用,考试也常考)

    练习日志:

    10.0.0.41 - - [03/Dec/2010:23:27:01 +0800] "HEAD /ch.jsp HTTP/1.0" 200 -
    10.0.0.43 - - [03/Dec/2010:23:27:01 +0800] "HEAD /cg.jsp HTTP/1.0" 200 -
    10.0.0.42 - - [03/Dec/2010:23:27:01 +0800] "HEAD /test.jsp HTTP/1.0" 200 -
    10.0.0.46 - - [03/Dec/2010:23:27:02 +0800] "HEAD /s.jsp HTTP/1.0" 200 -
    10.0.0.42 - - [03/Dec/2010:23:27:02 +0800] "HEAD /a.do HTTP/1.0" 200 -
    10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /b.html HTTP/1.0" 200 -
    10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /csj.jsp HTTP/1.0" 200 -
    10.0.0.47 - - [03/Dec/2010:23:27:02 +0800] "HEAD /jsa.jsp HTTP/1.0" 200 -
    10.0.0.41 - - [03/Dec/2010:23:27:03 +0800] "HEAD /do.jsp HTTP/1.0" 200 -
    10.0.0.46 - - [03/Dec/2010:23:27:03 +0800] "HEAD /checkstatus.jsp HTTP/1.0" 200 

    答案:

    方法一:

awk '{print $1}' apache.log|sort |uniq -c |sort -rn|head -10

    方法二:

awk '{++S[$1]} END {for(a in S) print a,S[a]}' apache.log |sort -k2

    3.统计访问请求中同一时间tcp状态排名.

    netstat -an 截取的一段 内容:

    tcp   0      0 202.34.35.123:80     222.221.145.251:2002   TIME_WAIT   
    tcp   0      0 202.34.35.123:80     121.207.188.230:1739   ESTABLISHED   
    tcp   0      0 202.34.35.123:80     210.38.1.84:4183       SYN_RECV   
    tcp   0      0 202.34.35.123:80     113.89.34.7:46474      ESTABLISHED   
    tcp   0      0 202.34.35.123:80     221.213.1.42:58778     LAST_ACK   
    tcp   0      0 202.34.35.123:80     203.208.60.195:54066   TIME_WAIT   
    tcp   0      0 202.34.35.123:80     60.12.201.67:8268      ESTABLISHED   
    tcp   0      0 202.34.35.123:80     113.125.75.149:58155   SYN_RECV   
    tcp   0      0 202.34.35.123:80     114.239.53.232:1198    SYN_RECV   
    tcp   0      0 202.34.35.123:80     59.37.230.66:2439      ESTABLISHED   
    tcp   0      0 202.34.35.123:80     110.18.8.117:2882      SYN_RECV   
    tcp   0      0 202.34.35.123:80     113.125.75.149:58161   ESTABLISHED   
    tcp   0      0 202.34.35.123:80     123.165.3.37:9698      SYN_RECV   
    tcp   0      0 202.34.35.123:80     113.125.75.149:58157   SYN_RECV 

    解答:

    方法二:

netstat -an|grep "^tcp"|awk '{print $6}'|sort |uniq -c |sort -rn

    方法三:

netstat -n|awk '/^tcp/ {++S[$NF]} END {for (a in S) print a,S[a]}'
posted @ 2014-12-31 11:35  1317660800  阅读(218)  评论(0编辑  收藏  举报