zoukankan      html  css  js  c++  java
  • awk数组详解

    在awk中,直接为数组中的元素赋值即可,示例如下。

    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";print huluwa[1]}'
    二娃

    为了方便示例,上例中使用了BEGIN模式,在BEGIN模式中,存在一个名为"葫芦娃"(拼音)的数组,我们在这个数组中放置了3个元素,第1个元素为"大娃",第2个元素为"二娃",第3个元素为"三娃",如果我们想要引用数组中第二个元素的值,只要引用下标为1的元素即可,正如上图所示,我们使用下标"[1]",获得了huluwa这个数组中第二个元素的值,即"二娃"。

    当然,如果你想要看到更多的"葫芦娃",可以在数组里面放置更多的元素。

    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";huluwa[3]="四娃";huluwa[4]="五娃";print huluwa[4]}'
    五娃

    由于命令太长,可读性可能会降低,为了在编写时提高命令的可读性,我们可以使用Linux命令行的"换行符"进行换行,Linux中,命令行的换行符为反斜杠"",上述命令换行后,如下

    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";
    > huluwa[3]="四娃";huluwa[4]="五娃";print huluwa[4]}'
    五娃

    可以看到,目前葫芦娃数组中已经存在6个葫芦娃了,我们可以获取到我们想要的葫芦娃,换句话说,我们可以通过数组的下标,获取到任何一个元素的值。

    我们知道,在动画中,五娃的超能力是"隐身",所以六娃也叫"隐身娃",那么,我们就把上述数组中的第5个元素的值设置为"空字符串"吧,用空字符串表示五娃已经"隐身"了,示例如下。

    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";
    huluwa[3]="四娃";huluwa[4]=" ";print huluwa[4]}'
     
    [root@server01 ~]# 

    既然在awk中,元素的值可以为"空",那么我们就不能再根据元素的值是否为"空"去判断元素是否存在了,所以,在awk中,如果你使用如下方法判断数组中的元素是否存在,是不合理的,如下图所示。

    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";
    huluwa[3]="四娃";huluwa[4]="五娃";print "数组5是不存在的"}'
    数组6是不存在的

    正如上图所示,第5个元素明明已经存在,但是通过上述方法判断元素是否存在时,仍然显示对应的元素不存在。

    其实,使用上述方法判断元素是否存在之所以不合理,除了上述原因,还有另外一个原因,就是当一个元素不存在于数组时,如果我们直接引用这个不存在的元素,awk会自动创建这个元素,并且默认为这个元素赋值为"空字符串",示例如下。

    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";
    huluwa[3]="四娃";huluwa[4]=" ";print huluwa[5]}'
    
    [root@server01 ~]# 

    如上图所示,数组中并没有第6个元素,但是当我们输出第7个元素时,输出了"空",所以,出于此原因,在awk中使用之前的方法判断元素是否为空也是不合理的,因为当我们引用一个不存在于数组中的元素时,这个元素其实已经被赋值为"空字符串"了,

    那么,在awk中,应该怎样判断元素是否存在呢?我们可以使用如下语法。

    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";huluwa[3]="四娃";huluwa[4]=" ";if(4 in huluwa){print "数据的第5个元素存在即可看到这句话"}}'
    数据的第5个元素存在即可看到这句话
    [root@server01 ~]# awk 'BEGIN{huluwa[0]="大娃";huluwa[1]="二娃";huluwa[2]="三娃";huluwa[3]="四娃";huluwa[4]=" ";if(9 in huluwa){print "数据的第5个元素存在即可看到这句话"}}'

    我们可以使用语法  "if(下标 in 数组名)" ,从而判断数组中是否存在对应的元素。

    在awk中,数组的下标不仅可以为"数字",还可以为"任意字符串",如果你使用过shell中的数组,你可以把awk的数组比作bash中的"关联数组",示例如下

    [root@server01 ~]# awk 'BEGIN{huluwa["dawa"]="大娃";huluwa["erwa"]="二娃";huluwa["shanwa"]="三娃";huluwa["shiwa"]="四娃";huluwa["wuwa"]="五娃";print huluwa["erwa"]}'
    二娃

    其实,awk中的数组本来就是"关联数组",之所以先用以数字作为下标的数组举例,是为了让读者能够更好的过度,不过,以数字作为数组下标的数组在某些场景中有一定的优势,但是它本质上也是关联数组,awk默认会把"数字"下标转换为"字符串",所以,本质上它还是一个使用字符串作为下标的关联数组

    使用delete可以删除数组中的元素,如下所示

    [root@server01 ~]# awk 'BEGIN{huluwa["dawa"]="大娃";huluwa["erwa"]="二娃";huluwa["shanwa"]="三娃";huluwa["shiwa"]="四娃";huluwa["wuwa"]="五娃";delete huluwa["erwa"];print huluwa["erwa"]}'
    
    [root@server01 ~]# 

    也可以使用delete删除整个数组,如下所示

    [root@server01 ~]# awk 'BEGIN{huluwa["dawa"]="大娃";huluwa["erwa"]="二娃";huluwa["shanwa"]="三娃";huluwa["shiwa"]="四娃";huluwa["wuwa"]="五娃";print huluwa["dawa"];print huluwa["erwa"];
    delete huluwa;print huluwa["dawa"]; print huluwa["erwa"]}'
    大娃
    二娃
    
    
    [root@server01 ~]# 

    到目前为止,我们已经介绍了怎样为数组中的元素赋值、怎样输出数组中的某个元素、以及怎样删除数组中的元素,那么现在,我们来聊聊在awk中怎样输出数组中的所有元素,在awk中,如果想要输出数组中的所有元素,则需要借助for循环语句,还记得在前文中介绍for循环时,有两种for循环语法吗?我们来回顾一下。

    #for循环语法格式1
    for(初始化; 布尔表达式; 更新) {
    //代码语句
    }
     
    #for循环语法格式2
    for(变量 in 数组) {
    //代码语句
    }

    这两种for循环语法都能够遍历输出数组中的元素,不过第一种for循环语法只能输出以数字作为下标的数组,示例如下

    [root@server01 ~]# awk 'BEGIN{huluwa[1]="大娃";huluwa[2]="二娃";huluwa[3]="三娃";huluwa[4]="四娃";huluwa[5]="五娃";huluwa[6]="六娃";huluwa[7wq]="七娃";for(i=1;i<=7;i++){print i,huluwa[i]}}'
    1 大娃
    2 二娃
    3 三娃
    4 四娃
    5 五娃
    6 六娃
    7 七娃

    你一定看出来了,我们利用了for循环中的变量"i"与数组中的下标都是"数字"的这一特性,按照顺序输出了数组中的元素值。

    那么,当数组中的元素的下标为"无规律的字符串"时,我们该怎么办呢?这时可以使用for循环的第二种语法,示例如下。

    [root@server01 ~]# awk 'BEGIN{huluwa["dawa"]="大娃";huluwa["erwa"]="二娃";huluwa["shanwa"]="三娃";huluwa["shiwa"]="四娃";huluwa["wuwa"]="五娃";huluwa["liuwa"]="六娃";huluwa["qi"]="七娃";for(i in huluwa){print i,huluwa[i]}}'
    liuwa 六娃
    shanwa 三娃
    shiwa 四娃
    wuwa 五娃
    erwa 二娃
    qi 七娃
    dawa 大娃

    注意,在这种语法中,for循环中的变量"i"表示的是元素的下标,而并非表示元素的值,所以,如果想要输出元素的值,则需要使用"print 数组名[变量]"

     当数组中的下标为"字符串"时,元素值输出的顺序与元素在数组中的顺序不同,这是因为awk中的数组本质上是关联数组,所以默认打印出的元素是无序的。

    那么你可能会提问了,既然之前说过,数字下标最终也会被转换成 "字符串",本质上也是关联数组,既然都属于关联数组,那么为什么第一种for循环语法能够按照顺序输出数组中的元素值呢?

    这就是以数字作为下标的优势,因为第一种for循环语法中的变量"i"为数字,由于for循环的原因,"i"是按照顺序递增的,当"i"的值与下标的值相同时,我们即可按照下标的顺序,输出对应元素的值,换句话说就是,我们是通过下标的顺序,输出对应元素值的顺序,也就是键值定位。但是,即使数组元素的下标为数字,如果使用第二种for循环语法,也不能够按照顺序输出,示例如下。

    [root@server01 ~]# awk 'BEGIN{huluwa[1]="大娃";huluwa[2]="二娃";huluwa[3]="三娃";huluwa[4]="四娃";huluwa[5]="五娃";huluwa[6]="六娃";huluwa[7wq]="七娃";for(i=1;i<=7;i++){print i,huluwa[i]}}'
    1 大娃
    2 二娃
    3 三娃
    4 四娃
    5 五娃
    6 六娃
    7 七娃

    awk中的数组本质上就是关联数组。

    前文中,我们都是手动的为数组中的元素赋值,那么我们能不能将指定的文本分割,然后将分割后的字段自动赋值到数组的元素中呢?答案是必须的,但是如果我们想要实现这样的效果,需要借助于split函数,而我们还没有介绍过函数,所以此处就先跳过了,不过需要提前说明的是,通过split函数生成的数组的下标默认是从1开始的,这就是为什么之前说,awk中数组的下标默认是从1开始的了。

    实例应用

    在实际的工作中,我们往往会使用数组,统计某些字符出现的次数,比如,我们想要统计日志中每个IP地址出现了多少次,我们就可以利用数组去统计。

    但是,统计的时候需要配合一些特殊用法,别着急,我们慢慢聊。

    在awk中,我们可以进行数值运算,示例如下

    [root@server01 ~]# awk 'BEGIN{a=1;print a;a=a+1;print a}'
    1
    2
    [root
    [root@server01 ~]# awk 'BEGIN{a=1;print a;a++;print a}'
    1
    2

    我们将变量a的值设置为1,进行加法计算,每次自加后,再次打印变量a的值,都会加1

    这并不难理解,因为上例中,a的值本来就是一个数字。

    那么,如果变量a的值是一个字符串,我们能否对变量a进行自加运算呢?我们来试试。

    [root@server01 ~]# awk 'BEGIN{a="test";print a;a=a+1;print a;a++;print a}'
    test
    1
    2

    在awk中,当变量a的值为字符串时,竟然也可以进行加法运算,从上例可以看出,awk中,如果字符串参与运算,字符串将被当做数字0进行运算。

    那么"空字符串"呢?当空字符串参与运算时,也会被当做数字0吗?我们来试试。

    [root@server01 ~]# awk 'BEGIN{a="";print a;a=a+1;print a;a++;print a}'
    
    1
    2
    [root@server01 ~]# awk 'BEGIN{a=" ";print a;a=a+1;print a;a++;print a}'
     
    1
    2

    看样子,我们猜的不错,空字符串在参与运算时,也会被当做数字0

    之前说过,当我们直接引用一个数组中不存在的元素时,awk会自动创建这个元素,并且为其赋值为"空字符串"。

    所以,如果我们引用一个不存在元素,并对其进行自加运算,那么会出现什么效果呢?我们来试一试

    [root@server01 ~]# awk 'BEGIN{print testarr["ip"];testarr["ip"]++;print testarr["ip"]}'
    
    1
    [root@server01 ~]# 

    当引用了一个不存在的元素时,元素被赋值为空字符串,当对这个元素进行自加运算时,元素的值就变成了1,因为,空字符串在参与运算时,被当做0使用了,所以,综上所述,我们对一个不存在的元素进行自加运算后,这个元素的值就变成了自加运算的次数,自加x次,元素的值就被赋值为x,自加y次,元素的值就被赋值为y,示例如下。

    [root@server01 ~]# awk 'BEGIN{print testarr["ip"];testarr["ip"]++;testarr["ip"]++;print testarr["ip"]}'
    
    2
    [root@server01 ~]# 

    利用这一点,我们就可以统计文本中某些字符出现的次数,比如IP地址,示例如下。

    [root@server01 ~]# cat test10
    192.168.1.1
    192.168.1.2
    192.168.1.3
    192.168.1.12
    192.168.1.3
    192.168.1.3
    192.168.1.2
    192.168.1.1
    192.168.1.2
    192.168.1.3
    [root@server01 ~]# awk '{count[$1]++}END{for(i in count){print i,count[i]}}' test10
    192.168.1.12 1
    192.168.1.1 2
    192.168.1.2 3
    192.168.1.3 4
    [root@server01 ~]#

    我们使用了一个空模式,一个END模式。

    空模式中,我们随便创建了一个数组,并且将IP地址作为引用元素的下标,进行了引用,所以,当执行到第一行时,我们引用的是count["192.168.1.1"]

    很明显,这个元素并不存在,所以,当第一行被空模式中的动作处理完毕后,count["192.168.1.1"]的值已经被赋值为1了。

    由于END模式中的动作会最后执行,所以我们先不考虑END模式。

    这时,空模式中的动作继续处理下一行,而下一行的IP地址为192.168.1.2

    所以,count["192.168.1.2"]第一次参与运算的过程与上述过程同理。

    其他IP地址第一次参与运算的过程与上述过程同理。

    直到再次遇到相同的IP地址时,使用同样一个IP地址作为下标的元素将会再次被自加,每次遇到相同的IP地址,对应元素的值都会加1。

    直到处理完所有行,开始执行END模式中的动作。

    而END模式中,我们打印出了count数组中的所有元素的下标,以及元素对应的值。

    此刻,count数组中的下标即为IP地址,元素的值即为对应IP地址出现的次数。

    最终,我们统计出了每个IP地址出现的次数。

    其实,我们就是利用了之前所演示的一个知识点:

    我们对一个不存在的元素进行自加运算后,这个元素的值就变成了自加运算的次数

    上述过程可能比较绕,如果你之前没有接触过awk,一遍看不懂是很正常的,自己按照上述过程动手做几遍,细细品味一番,相信你会搞明白的。

    如果你以后再想统计文本中某类文本出现的"次数",就可以使用上述套路了,活学活用以后,你会发现上述套路特别好使。

    比如,如果我们想要统计如下文本中每个人名出现的次数,我们则可以使用如下命令。

    [root@server01 ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}} END{for(j in count){print j,count[j]}}' test4
    Tyler 1
    Angel 1
    James 1
    Lucas 1
    William 1
    Thomas 1
    Green 1
    Jack 1
    Phillips 1
    Kevin 2
    Lee 2
    Allen 1
    Aiden 1
  • 相关阅读:
    SEO优化技巧:16个方法优化网页中的图片
    《Google官方SEO指南》十一:以恰当的方式推广你的网站
    ASP.NET Eval如何进行数据绑定
    浅析ASP.NET页面缓存的几点体会
    浅谈ADO.NET中的五个主要对象
    WCF 入门 WCF基础知识问与答
    Hibernate第一次课(1)
    谷歌、雅虎支持中文域名搜索 有助提升SEO
    告诉SEO初学者:百度收录并非终极目标
    WF 创建 SQL 持久性数据库
  • 原文地址:https://www.cnblogs.com/liujunjun/p/14201144.html
Copyright © 2011-2022 走看看