awk我们都是知道的,它是一个文本格式化工具,可以用来从日志或命令输出的数据中统计信息,并生成报告。  所以我们都叫它报告生成器。


一、 认识awk.

  • 是以字段为单位 以行为一个区间来处理的。各字段默认是以空格和TAB键区分。

  • 会在命令刚开始的时候把一行的数据分段赋给变量$1 $2 $3 $4......

  • 一个变量代表的是一字段。$0 代表的是一整行。

  • 不会略过空白行。

  • linux上的awk程序gawk, 是由GNU加强版的awk, 为了方便使用,符号链接为awk.


    awk [options] 'pattern{action}' FILE ....

    

    -F 用来指定输入的字段分隔符。


    pattern:我们姑且就叫这个吧,有以下几种:

        地址定界 

        模式        包括正则表达式

        表达式

        BEGIN     命令执行前预处理操作

        END      命令执行后的操作


    只有pattern通过,才会执行{action}, 可以理解为是一个组合,这种组合可以有多个,而且pattern还是可省的,比如 我不用再匹配什么东西,只要执行动作就可以。


    action:  

        定义变量,数组

        语句: if, while, for

        输出: print, printf


    awk内置的变量:

         NF : 当前处理行一共多少字段

         FS : 输入字段分隔符     默认空格

        OFS : 输出字段分隔符     默认空格

         NF : 每一行所拥有的字段总数。 

         NR : 目前awk所处理的是第几行数据。 


    awk内置函数:
        int() 截取整数



二、简单使用

    例1:简单例子

[star@Main ~]$ awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
.........

        这就是一个简单的例子,-F 来指定输入分隔符, 我们知道/etc/passwd文件中都是以:来分隔各个段的,所以这里就是了。  然后就是动作, print 显示第一个字段和第三个字段。

        print item1,item2,......     

        print的使用是以项目来区分的, 不同的项目之间以逗号分隔, 显示的时候不同的项目之间以输出字段分隔符来分隔。


        (注意:无论模式还是动作都一定要在''单引号中,要不然经过shell的时候可能就变了,如$1,$3,bash会把它们当做变量来处理的,处理以后 再给awk。 我们在终端输入的所有东西都是由shell来替我们执行的。 比如启动程序)


    例1.5:模式

-bash-4.1# awk -F: '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

        因为忘了介绍模式,所以后加的例子。 模式只要写在//里面就可,用来表示某些数据, 这里就是表示 root的字符串。 ^是正则表达式里的,表示行头, 不懂的话可不行啊, 正则表达式是必须的。 一行数据只要有/^root/所表示的数据,那么就执行后面的动作。 单独的print会输出整行。


    例2:BEGIN

[star@Main ~]$ awk 'BEGIN{FS=":"}{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
...........

        把-F: 去掉,效果也还是一样的。 上面我们说了,输入字段分隔符是FS,awk就是从这个变量来区分不同字段的分隔的。 而-F: 其实也是这么个意思。 那么只要我们手动的把FS的值改成冒号就可以了。 那么BEGIN呢,它的意思就是在awk在实际工作之前执行一次,在这里也就是大括号里的FS赋值了。  关于BEGIN大家可能有点疑问,那么再举了例子。

    例3:BEGIN

[star@Main ~]$ awk '{FS=":"}{print $1,$3}' /etc/passwd
root:x:0:0:root:/root:/bin/bash         #注意这里
bin 1
daemon 2
adm 3
lp 4
sync 5

        为什么第一行是那个样子, 是因为没有以冒号分隔。 而它的工作过程是:1. 没有BEGIN出现,不用事前执行一些动作。 2. awk开始获取第一行数据,以FS值为分隔符,此时的FS是空的,$0变量保存整行数据,$1保存第一个字段数据,$2保存第二个字段数据.........一直到最后。 3. awk开始执行动作,3.1. FS=":" 。 3.2. 显示$1,$3。  4. 获取第二行数据,以FS值冒号为分隔符............。


        看明白了吗,在FS赋值之前就已经把第一行数据获取完毕了。 所以 在有BEGIN的情况下,awk在获取数据之前会执行一次BEGIN的动作, 而且只有这一次。 那么END应该也明白是什么功能了吧,就是在操作完所有行数据以后所执行的一次动作。



    例4: NR,地址定界

[star@Main ~]$ awk 'BEGIN{FS=":"}NR==5,NR==8{print $1,$3,"\t\t","This is",NR,"line"}' /etc/passwd
lp 4 		 This is 5 line
sync 5 		 This is 6 line
shutdown 6 		 This is 7 line
halt 7 		 This is 8 line

        1. NR是表示第几行,上面就是第5行到第8行的定界。

        2. 在print里面除了变量以外,其它字符都要加上引号。 \t表示一个制表符的位置,TAB。


        3. 在print里不同的项目输出的时候会以输出字符分隔符隔开,至于一个项目有什么东西,在书写正确的情况下 随便。如: print $1"\t",$2"This test"。

        4. NR变量表示awk所执行的第几行。 所以宽泛的讲  NR 就是表示行号。


        5. 除了表示字段数据的$0,$1,$2....., 其它变量包括自定义变量都不用$号。 可以理解为$0之类的就是一个整体, 而不是bash中的变量引用。



    很明显都可以看出来,上面的显示糟糕透了,乱,没有整体性。 那么可以用printf。


printf "format",data1,data2,.......

format: printf有很多的格式字符,这里只显示常用到的了。


        \n 换行

        \t 水平TAB键


        %s    显示字符串。    数值也可以当作字符串显示

        %d,%i 十进制整数。

        %c    显示字符ASCLL码。

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

        %f    浮点数显示。

        %n.mf      n表示包括小数点在内的所有长度,m表示小数点后的长度。

        %%    显示%自身。

        %u    无符号整数

修饰符:

        -    左对齐

        +    显示数值符号

        0    以0代替多余的空格。


    例5:printf

[star@Main ~]$ awk 'BEGIN{FS=":"}NR==5,NR==8{printf "%-10s %5s %10s %2i%5s\n",$1,$3,"This is",NR,"line"}' /etc/passwd
lp             4    This is  5 line
sync           5    This is  6 line
shutdown       6    This is  7 line
halt           7    This is  8 line

        这样就规整多了, format后面的数据会一个一个的套用在format里面的格式字符中,一切都是按格式字符输出的,如果只有一个格式字符,不管后面多少个数据, 那么最后显示的也还是第一个数据。  注意一点的是: printf不会自动换行,所以后面加了个\n。 还有就是引号的问题,它们是字符,所以要在引号中。

        这些格式大家可以试试看效果,那个 “-” 是左对齐。可以试试去掉以后的效果,再试试换成0以后的效果, 就会明白格式是怎么回事了。


    例6:表达式

[star@Main ~]$ awk 'BEGIN{FS=":"}$3>=500{printf "%10s %5s %10s %2i%5s\n",$1,$3,"This is",NR,"line"}' /etc/passwd
      star   500    This is 25 line
     vuser   501    This is 27 line

    例7:匹配

[star@Main ~]$ awk 'BEGIN{FS=":"}/bin\/bash/{printf "%10s %5s %15s %10s %2i%5s\n",$1,$3,$7,"This is",NR,"line"}' /etc/passwd
      root     0       /bin/bash    This is  1 line
      star   500       /bin/bash    This is 25 line

    查找有/bin/bash的行数据,并执行后面的动作。


    例8:添加说明信息

[star@Main ~]$ awk 'BEGIN{FS=":";printf "%-10s %5s %15s %15s\n","USER","UID","SHELL","DESCRIPTION"}/bin\/bash\>/{printf "%-10s %5s %15s %10s %2i%5s\n",$1,$3,$7,"This is",NR,"line"}' /etc/passwd
USER         UID           SHELL     DESCRIPTION
root           0       /bin/bash    This is  1 line
star         500       /bin/bash    This is 25 line

    比上面就多了一行描述信息。 也是在BEGIN里面的动作。


    下面我们试试用算术表达式和自定义变量:

    比如我这里随便写了个成绩单, 要在最后加上total 总计算各位同学的总成绩。

User    English   Math   Music   
zhangsan   85     90      83    
lisi     80      95     60    
zhouwu    66    77       98     
zhengwang   80   93    67      
xiaoli   60     85      99      
xiaowei   33      98     56

    例9:算术,自定义变量

[star@Main ~]$  awk 'NR==1{printf "%-10s %7s %6s %6s %6s\n",$1,$2,$3,$4,"Total"}NR>=2{total=$2+$3+$4;printf "%-10s %7s %6s %6s %6s\n",$1,$2,$3,$4,total}' info
User       English   Math  Music  Total
zhangsan        85     90     83    258
lisi            80     95     60    235
zhouwu          66     77     98    241
zhengwang       80     93     67    240
xiaoli          60     85     99    244
xiaowei         33     98     56    187

        怎么样,看起来还可以吧。 来看一下过程: 1. NR==1的时候就是表示在第一行的时候,printf后面的数据,自己指定了一个字符串“Total”, 左边的格式符也是对应的。 然后第一行结束后, 在NR>=2 也就是大于或等于第二行的时候,就开始执行后面的动作了。


        然后从第二行开始就开始total变量,它的值就是由$2,$3,$4加起来以后的值。然后以分号结束这个语句,开始printf的动作。 自定义变量是不用加$符的,也不能用引号引起来,引起来就成字符串了。 


    说明一下动作里面的分号吧:

        1. 分号的作用是把不同的语句分开。

        2. 没有pattern的不同的动作,也就是多个没有pattern的大括号,基本上跟分号是一样的。

        3. 区别就是,有pattern的动作里面可以有多个语句。满足条件以后就可以执行不同的多个语句。

        4. 分号也可以用回车来代替。


    命令虽然长点,但是都是一些东西组合起来的,只要拆开来看就简单了。


其实total在这里也可以不加的,如:

[root@localhost ~]# awk 'NR==1{printf "%-11s%9s%6s%6s%7s%5s\n","User","English","Match","Music","Total","AVA"}NR>1{printf "%-11s%9s%6s%6s%7s%5d\n",$1,$2,$3,$4,$2+$3+$4,($2+$3+$4)/(NF-1)}' info
User         English Match Music  Total  AVA
zhangsan          85    90    83    258   86
lisi              80    95    60    235   78
zhouwu            66    77    98    241   80
zhengwang         80    93    67    240   80
xiaoli            60    85    99    244   81
xiaowei           33    98    56    187   62

这里又多加了一个平均值。




二、复杂应用.

        以上面的使用方式来格式化显示一些简单的数据还可以,可要分析日志或统计数据就不行了,如 某某出现了多少次,几点到几点有多少人访问主页 等等。

        这部分的内容有点复杂,再加上我也不会怎么写东西, 可能读者朋友看起来会有点困难。 嗯,我只是在打提前量。 


1.操作符


    比较操作符:注意如果是字符串,只能用~之类的进行区配,不能用==。

x x<=y x>y x>=y x==y x!=y x~y x!~y
x小于 小于等于 大于 大于等于 等于 不等于 匹配 不匹配

    算术操作符:

-x x^y x**y x*y x/y x+y x-y x%y
x变负值 次方 次方 取余

    赋值操作符:

x=y += -= *= /= %= ^= **= ++ --
赋值 x=x+y x=x-y x=x*y x=x/y x=x%y x=x^y x=x**y x=x+1 x=x-1

    逻辑关系符(与,或): &&    ||


例:匹配操作符


[root@localhost ~]# awk -F: '$7~"/bin/bash$"{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
star:x:1000:1000:star:/home/star:/bin/bash
tomcat:x:1001:1001::/home/tomcat:/bin/bash


[root@localhost ~]# last | awk '$0!~/^$/&&$0!~/^reboot/&&$2!~"tty"&&$0!~/^wtmp/{print}'
root     pts/0        172.16.40.2      Sun Apr 10 10:25   still logged in   
root     pts/0        172.16.40.2      Sat Apr  9 15:49 - 22:50  (07:01)    
root     pts/0        172.16.40.1      Fri Mar 25 23:23 - 23:23  (00:00)    
root     pts/0        172.16.40.1      Fri Mar 25 23:23 - 23:23  (00:00)    
root     pts/1        172.16.40.1      Thu Mar 24 17:57 - down   (00:00)



    例10:输出重定向

-bash-4.1# last | grep "Jan" | awk '$0!~/^$/ && $1~/star\>/{print $1,$3 >> "/tmp/star"}$0!~/^$/ && $1~/root\>/{print $1,$3 >> "/tmp/root"}'

        我们拆开分析下: 

awk '$0!~/^$/ && $1~/star\>/

        1. $0 表示的是一行数据。 ^$是一个正则表达式,表示空行, 它在这里的作用是来表示空行的。 然后$0!~/^$/就是说在这一行数据不是空行的情况下, 注意!~只是运算符表示不匹配某些东西。    $1~/star\>/  第一个字段匹配star的情况下。  中间的&& 是与运算符。  连起来就是:在$0不是空行,$1是star的情况下。

        2. 后面的>>就不用说了吧,大家都是学linux的。路径一定要用引号引起来。 

        3. 所以   这个例子就这样了。


2.判断语句

    例11:if-else

-bash-4.1# awk -F : '{if ($3==0) {printf "%-9s %13s\n",$1,"Administrator"} else {printf "%-9s %13s\n",$1,"Common User"}}' /etc/passwd
root      Administrator
bin         Common User
daemon      Common User
adm         Common User
lp          Common User
sync        Common User

        如果()则{},否则{}。    在控制语句中,条件要在()中。  这个大括只是由语句所发出的动作,一种动作的集合。 跟最外面的大括号可不一样的。 

        既然是动作的集合了,那么也就是可以有多个动作,以分号隔开。那么就成了:

        if(){action1;action2;...}else{action1;action2;....}

-bash-4.1# awk -F : '{if ($3==0) {printf "%-9s %13s\n",$1,"Administrator";print} else {printf "%-9s %13s\n",$1,"Common User";print}}' /etc/passwd
root      Administrator
root:x:0:0:root:/root:/bin/bash
bin         Common User
bin:x:1:1:bin:/bin:/sbin/nologin
daemon      Common User

        面且在只有一个动作的情况下,里面的大括号是可以省略的,那么就成了这个:

-bash-4.1# awk -F : '{if ($3==0) printf "%-9s %13s\n",$1,"Administrator"; else printf "%-9s %13s\n",$1,"Common User"}' /etc/passwd
root      Administrator
bin         Common User
daemon      Common User
adm         Common User

        与else之间用分号隔开, 注意 一个语句和它的动作千万不能分开。else相当于是另一个语句了。

        如果是字符串要用~进行匹配。如: if ($1~/mogilefs/)

    例12:计数,查看UID小于500的用户数

-bash-4.1# awk -F : '{if ($3<500) count++}END{ print "User count:",count}' /etc/passwd
User count: 32

        $3也就是UID的段,只要是UID小于500的行, count就加上1.  结果就是UID小于500的用户数。



3.循环语句:

    

        循环的是什么呢, 是字段。 awk本身就是编历所有行的, 而且awk的工方式就是把一行的数据拿过来,然后开始动作。 我们的动作是循环那也是这一行的数据,这一行中的所有段。

        在没有循环之前,如果想要判断文件中的哪个字段的值等于"abc"。 怎么做,用模式匹配"abc"吗,结果是知道了某一行中有没有"abc",却没有办法做到只显示"abc"那个字段。

        还有,我们只能判断指定字段的值是否是什么什么,而不能做到一个字段一个字段的去对比。

        这就是循环其中的一项功能了。


    例13:while

[star@Main ~]$ awk -F : '{i=1;while (i<=NF) {printf "%s ",$i;i++}}{printf "\n"}' /etc/passwd
root x 0 0 root /root /bin/bash 
bin x 1 1 bin /bin /sbin/nologin 
daemon x 2 2 daemon /sbin /sbin/nologin 
adm x 3 4 adm /var/adm /sbin/nologin

        这里想要表达的意思就是while的用法。 还有 printf "\n" ,有时候想要输出换行,print就直接显示整行数据了,所以就用printf "\n"了。

        单独坽出来printf "\n"是因为它必须要在循环结束以后出来,不然就是每一个字段一换行了。


        i=1来定义循环初始值, while后面一直到{printf "\n"}之前,都是与while一体的,小括号里的是条件, 再后面就是动作了。 因为动作不是只有一个,所以就用了大括号来括起来。 一定要注意i++,这个一定要在while语句范围里啊, 要不然你懂的。


        上面每一个空格隔开的都是一次循环, 这是一个字段一个字段贴上来的。

        NF表示这一行的字段数,要知道 如果有7段的话,那么最后一段就是$7。所以只在小于或等于7的时候循环。


        对了,说明一点,因为有时候可能会混。 假如NF的值为7, 那么$NF是什么意思呢。 $7 第七个字段的意思。 所以要区分好 NF , $NF。 


    例14:深入使用

[star@Main ~]$ awk 'NR==1{printf "%-10s %7s %6s %6s\n",$1,$2,$3,$4}NR>=2{i=2;while(i<=NF){if ($i<80) $i=" ";i++};printf "%-10s %7s %6s %6s\n",$1,$2,$3,$4}' info 
User       English   Math  Music
zhangsan        85     90     83
lisi            80     95       
zhouwu                        98
zhengwang       80     93       
xiaoli                 85     99
xiaowei                98

        这个还是上面我们的那个成绩单, 只显示大于等于80的分数。 只要把小于80的字段置空就可以了。


:如果还要显示正常情况下的总值与平均值的话。

[root@localhost ~]# awk 'NR==1{printf "%-12s%9s%7s%8s%8s%5s\n",$1,$2,$3,$4,"Total","AVA"}NR>1{total=$2+$3+$4;i=2;while (i<=NF) {if ($i<80) $i="";i++};printf "%-12s%9s%7s%8s%8d%5d\n",$1,$2,$3,$4,total,total/(NF-1)}' info
User          English   Math   Music   Total  AVA
zhangsan           85     90      83     258   86
lisi               80     95             235   78
zhouwu                            98     241   80
zhengwang          80     93             240   80
xiaoli                    85      99     244   81
xiaowei                   98             187   62



    例15:do while

[star@Main ~]$ awk -F : '{i=1; do {printf "%s ",$i;i++} while (i<=NF) {printf "%s ",$i;i++}}{printf "\n"}' /etc/passwd
root x 0 0 root /root /bin/bash  
bin x 1 1 bin /bin /sbin/nologin  
daemon x 2 2 daemon /sbin /sbin/nologin  
adm x 3 4 adm /var/adm /sbin/nologin

        先执行一次操作,再做循环,基本用不上,不用关注它。 用while就够了。


    例16:for

[star@Main ~]$ awk -F: '{for (i=1;i<=NF;i++) printf "%s  ",$i}{printf "\n"}' /etc/passwd
root  x  0  0  root  /root  /bin/bash  
bin  x  1  1  bin  /bin  /sbin/nologin  
daemon  x  2  2  daemon  /sbin  /sbin/nologin  
adm  x  3  4  adm  /var/adm  /sbin/nologin

        for循环看起来简洁多了, 也容易看明白。  而且for还有另外的一个功能。就是编历数组元素。


在循环语句或者是case语句中 bread和continue 也可以用,跳出循环和跳过本此循环。 

case语句不常用,在这里就不说了。



next 结束对本行数据的处理。与continue的不同就是: 是退出本行而不是本此循环。

如:

[star@Main ~]$ awk -F: '{if ($3!=0) next; print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

        不管是把$3=0当做模式写在{}的前面来匹配行,还是像现在一样写在if语句里面,$3不等于0的行就跳过。awk都是一行一行的去操作的,它的工作模式就是这样的。



4.数组。

        我们这里主要是关于“关联数组”的, 关联数组就是以自定义的字符串来作下标的数组,而不是以数字来作下标。  如:  abc["Hello"]    abc数组的Hello索引。 在awk中自定义的下标必须要加上引号。


        有了关联数组就可以开始统计数据了。

    例17:关联数组,统计数据

[star@Main ~]$ awk -F : '{bash[$NF]++}END{for (i in bash) printf "%-18s %3i\n",i,bash[i]}' /etc/passwd
/sbin/shutdown       1
/bin/bash            7
/sbin/nologin       24

        bash[$NF], $NF就是最后一个字段,它的值可以是/bin/bash, 那么就成了bash["/bin/bash"],不要纠结于/bin/bash应该没有引号,awk自己处理的下标不用我们操心。


        bash["/bin/bash"]++, 所有的空变量或数组在经过算术运算的时候,都会当成0来计算。

        所以,bash["bin/bash"]现在的值就是1,再出现一次/bin/bash,它的值再加1。


        那么如果是别的如:/sbin/nologin, 就是 bash["sbin/nologin"],bash数组多了一个下标而已, 同样的,现在是1,再出现一次就会再加1 。 

        所有行都执行完毕以后,bash数组就是以各个shell为下标的数组,而每个shell下标的值就是出现了多少次。


        for (i in bash) , 以bash数组中的下标为i赋值,直到bash的所有下标都用过了,循环结束。 而每一次循环, 就printf显示 i 和 bash[i]。 效果就是: 如果i 是/bin/bash,那么bash[i]也就是bash["/bin/bash"]的值。  循环一次就显示一次,直到for读取完所有下标。


        OK,上面是统计的各个shell的用户有多少个。



那么,可不可以对数组中的值排序呢,如上面的1 7 24。(这些是在后来复习的时候加上的,所以与上面的数据不一样)。

[root@localhost ~]# awk -F: '{shell[$NF]++}END{for (i in shell) printf "%-15s%5d\n",i,shell[i]}' /etc/passwd
/bin/sync          1
/bin/bash          3
/sbin/nologin     23
/sbin/halt         1
/sbin/shutdown     1

让第二列的值从小到大排序:可以使用内置函数asort或者是asorti。这里就分别说明一下它们的不同。

先来看一下asort的例子:

[root@localhost ~]# awk -F: '{shell[$NF]++}END{asort(shell,ss);for (i in ss) printf "%-15s%5d\n",i,ss[i]}' /etc/passwd
4                  3
5                 23
1                  1
2                  1
3                  1

使用方式:asort(array0,array1) ,会把array0这个已存在的数组中的值进行排序,并存入array1这个数组中,键是从1开始的数字。array0不会发生变化。 那么结果就是在新的数组中所存储的就是老数组所有键的值经过排序以后的结果。只不过是索引数组。丢失了原来的键。 

看一下上面的键值对应就容易看明白了。

当然这个函数还是有返回值的,会返回新的数组的键值有多少个。

[root@localhost ~]# awk -F: '{shell[$NF]++}END{len=asort(shell,ss);for (i=1;i<=len;i++) printf "%-15s%5d\n",i,ss[i]}' /etc/passwd
1                  1
2                  1
3                  1
4                  3
5                 23

上面的len变量就是存储了最大索引键数字。后面就可以以这个为条件从1到后依此的显示键值了。

但不管怎么说,上面不显示shell类型,这用起来也太不方便了。


asorti  对数组下标进行排序。记录到这里才发现这个是对下标进行的排序,暂时也不知道怎么解决排序了。如下面这个是对shell进行的排序。j_0068.gif

[root@localhost ~]# awk -F: '{shell[$NF]++}END{len=asorti(shell,ss);for (i=1;i<=len;i++) printf "%-3s%-18s%3s\n",i,ss[i],shell[ss[i]]}' /etc/passwd
1  /bin/bash           3
2  /bin/sync           1
3  /sbin/halt          1
4  /sbin/nologin      23
5  /sbin/shutdown      1




    例18:

[star@xingxingwo ~]$ ss -tna | awk '$1 !~ /^$/ && $1 !~ /State/ {state[$1]++}END{for (A in state) printf "%-10s %2i\n",A,state[A]}'
SYN-RECV    2
LISTEN      4
ESTAB       2
TIME-WAIT   2

        

    例19:


[root@xingxingwo logs]# tail -n 5 access_log 

000.000.000.000 - - [12/May/2015:21:21:02 -0400] "GET / HTTP/1.0" 200 288

000.000.000.000 - - [12/May/2015:22:21:07 -0400] "GET / HTTP/1.0" 200 288

    如果我们要统计httpd日志中的被访问网址。 就是上面那个/的位置。

awk从简单到复杂_第1张图片

        上面看起来有点奇怪,因为网址后的参数也在里面,同一个网址却因为参数的不同而出现了两次。  如果可以只显示?号之前的网址就好了。

那么我们就可以用split函数了。


5.内置函数。

        我们就只学一个。 split(string,array[,fieldsep,...]

        split会将string的字符串,以fieldsep分隔符分段, 并将分段后的数据存入数组array中,数组的下标是以1开始。

        这个不是关联数组,是普通的以0,1,2,3,...为下标的数组。每个字段的数据都会填入一个下标, 而填入的时候是以下标1开始的。 也就是直接以下标1开始赋值。


    例19:

[root@xingxingwo logs]# awk '$0!~/^$/{split($7,count,"?");addr[count[1]]++}END{for (i in addr) printf "%-29s %6s\n",i,addr[i]}' access_log 
/robots.txt                       33
/cgi-bin/authLogin.cgi             1
/caca2.txt                         1
/cgi-bin/php.cgi                   2
http://24x7-allrequestsallowed.com/      3            #
http://testp4.pospr.waw.pl/testproxy.php      1
/"                                 7
/favicon.ico                      93
/cgi-bin/php5-cli                 16
/muieblackcat                      2
/includes/templates/error.tpl      1
/cgi-bin/php-cgi.bin               1
/cgi-mod/index.cgi                19
//myadmin/scripts/setup.php        2
/cgi-bin/php                      21
/cgi-bin/login.cgi                18

        以?为分隔,把日志中的$7字段分割并给数组count,以count[1]开始赋值。 如果没有?号则不会分割,直接把$7给count[1]。  而count[1]里面存储的就是被访问的网址。

        所以上面我们只要count[1]的值为下标给另一个关联数组就可以了。 

        这里可能就有点乱了,多多练习吧。  


删除关联数组变量:  delete array[index]    

如上面的统计shell的那个,我们就可以在数组统计完成以后,或者在统计过程中,把下标为/bin/bash的删除了。

[star@Main ~]$ awk -F : '{bash[$NF]++}END{delete bash["/bin/bash"];for (i in bash) printf "%-18s %3i\n",i,bash[i]}' /etc/passwd
/sbin/shutdown       1
/sbin/nologin       24
/sbin/halt           1
/bin/sync            1

awk里面有太多东西,很多都不知道怎么使用,这里也只是一部分常用到的。 还有很多变量、内置函数,还有自定义函数也都没有用过。 大家有兴趣可以自己去查找资料。


有很多东西也只是前几天刚学的, 而且自己也很少写东西, 所以如果朋友们有疑问,希望可以尽可能的提出来。 谢谢大家