0x0A 数据琅琊棒,伪装者AWK

作者: i败火 | 来源:发表于2015-12-30 22:17 被阅读531次

    摘要:AWK是命令行下文本处理非常实用的工具。这便是“一个分隔,两种结构,三段布局”的全部。awk是伪装成实用工具的一门编程语言,我们姑且把awk当成数据分析的琅琊棒来使用吧!

    0x0A.jpg 00 开篇
    琅琊榜首,江左梅郎。今年电视剧最热的恐怕是追梅郎的剧了。以前没有看过梅郎的电视,这次却又追完了伪装者。而“云戒云”的公众号,也缘起于两部剧中的两位演员……。

    也许会让你失望,本篇不是影评,也不是观影心得,而是关于数据分析的。在数据分析领域里面,每个人都有自己得心应手的工具,也许你的工具是R,也许是Excel开始,也许是SPSS,而在下却是从AWK开始起步。

    AWK是Linux和Unix下默认提供一个非常实用的工具,名字由三位创始人的名字各取一个字母组成,并没有实际意义。AWK是命令行下文本处理非常实用的工具,如果你写过或者读过一些she本,基本里面也会包含大量的awk命令。因为用它处理一些任务,确实很方便。

    有很多数据,为CSV格式,即每个字段之间以逗号进行分隔,可以从Excel中直接导出csv格式,也可能是其它地方直接产生的数据。csv是一种通常的文件格式,而xls不是。你可以把awk当成程序员的Excel,或者命令行下的Excel处理工具。

    01 一二三要点
    你通常看到的awk命令会是如下:

    awk -F',' 'BEGIN{count=99}/$2~/1=1/{print $5; count++}END{print count}' data.csv
    

    上面一条简单的命令,包含了大量awk的基础知识。让我们慢慢来解析,且先记住:一个分隔,二种结构,三段布局。

    命令中的-F','指示了数据字段之间以逗号进行分隔,awk默认会识别空白为分隔,空白包括了tab和空格。指定一个分隔符,是awk处理表格数据的基础。分隔后的字段,会存储在特殊的以$开头的变量(也叫缓冲)中,$1为第一个字段,$2为第二个字段,以此类推。$0为全部字段,即整个记录。

    awk的一个核心概念是Pattern和Action,即模式与处理。awk按行读取数据和进行处理,读入当前行,进行模式匹配,如果匹配上,进行相应的处理。如果匹配不上,则读入下一行,直接文件结束。比如模式为判断当前行的第二字段是否包含字符串“1=1”,模式即为$2/1=1/,即是表示正则匹配,表示不匹配可以用:!~ 符号。除了正则,还有以下几种模式:

    1. BEGIN, END                            # 特殊模式
    2. $1 ~ /^love.*$/                       # 正则模式
    3. $1 == "1.2.3.4"                       # 逻辑判断
    4. /start/, /end/                        # 区块匹配
    5. $1 == "1.2.3.4" && $5 ~/^360se.*$/    # 组合(逻辑,正则)
    
    知识星球.jpeg

    第三种模式,是简单的逻辑相等判断,判断第一个字段是否等于1.2.3.4这个ip地址。第四种区块匹配,两个匹配之间用逗号分隔。不同于通常的按行匹配,是指awk在全部行的基础上,匹配第一个正则的行作为数据块的起始行,匹配第二个正则的行作为数据块的最后一行,后面的处理基于中间匹配的这些行进行操作。第五种是对前面几种模式通过逻辑&&与||进行组合。

    BEGIN与END可以算成是一种特征的模式了,主要作用于文件的预处理和最后收尾工作。BEGIN常用于对变量的初始化或者文件处理之前打印一些特殊的标记。而END通常更有用一些,尤其是在循环结束后,可以获取循环处理的结果。

    上面示例中,BEGIN{count=99} 这一段,是一个典型的Pattern和Action结构,BEGIN为特殊tern,大括号内为Pattern对应的Action,这个地方只是简单的初始化变量为99。/$2~/1=1/{print $5; count++}这一段,为我们代码的核心,Pattern为/$2~/1=1/,即判断第二个字段是否包含1=1这个字符串。如果包含,则打印第5个字段,并且给变量count的值加1。END{print count}这一段,是在处理完整个文件后,打印最后的count值。

    这便是“一个分隔,两种结构,三段布局”的全部。开始的时候,使用BEGIN布局,进行一些初始化。中间是核心的处理与统计,按行读入数据,进行Pattern匹配,对匹配上的行进行相应的Action。文件处理完了,使用END布局,打印需要的数据。

    02 一个示例

    下面是一个统计自己命令使用习惯的简单命令:

    history | awk '{cmd[$2]++;count++;}END{for(a in cmd)printf("%s\t%s\t%.2f%%\n", a, cmd[a], cmd[a]*100/count)}' | sort -k2 -nr | head
    

    awk 182 18.22%
    cd 137 13.71%
    less 97 9.71%
    rm 81 8.11%
    scp 51 5.11%
    cat 43 4.30%
    e 33 3.30%
    ssh 28 2.80%
    fgrep 28 2.80%
    mv 25 2.50%

    上面命令中,awk使用了默认的空白分隔字段,取history命令输出的第二个字段为命令,统计每个命令使用次数和总次数,使用一个一维数组来存储每个命令的次数。END之后,使用了for循环,读取每个命令和使用的次数,计算一个使用率,最后打印输出。sort只是进行排序,head用于显示最10条数据。

    03 应用与统计

    awk是一种通用的文本文件处理工具,除了常用的数据统计功能外,还能进行数据格式验证、数据格式处理、数据抽取等等任务。

    比如,验证第三个字的值是否在1-20范围内,可以打印出不符合要求的数据来验证,使用了默认处理{print $0}(不指定Action则使用默认的Action):

    awk -F',' '$3<1 || $3>20' data.csv
    

    awk中的命令串使用单引号包住,是避免其中的一些符合被shell解析,那么在awk中使用单引号就显得比较麻烦了,需要先对单引号进行转义,再使用一对单引号包住,最后使用一对双引号进行包住:

    awk 'BEGIN{print "'\''"}'
    

    当然,awk不仅在可以以单行命令的方式使用,如果你的程序大了,在一行上写出来难免很难调试(话说awk本来就很难调试),也可以写在脚本中,使用awk -f script.awk data.csv进行调用,-f参数表示命令来源于文件:

    awk -f
    {print "'";
    }
    

    引用shell的参数:

    $ awk -v name="yunjie-talk" 'BEGIN{print name}'
    $ yunjie-talk
    

    也许你需要处理一个大日志文件,只想随机抽取其中一些样本来进行分析,可以使用:

    awk 'rand()<0.1'  log.csv > sample.csv
    

    在模式中,使用了rand()函数来随机产生0,1之间的小数,只有当前产生的值小于0.1才打印当前行,即只随机抽取10%的数据作为样本。

    在一些流量统计中,会需要统计每分钟的请求量:

    $ cat 20151227.log.gz | gzip -d | awk '{print strftime("%H:%M", $1)}' | sort | uniq -c | sort -nr | head
    

    12984 20:19
    12582 20:35
    12382 19:57
    12350 20:22
    12159 19:45
    11878 20:20
    11815 20:18
    11621 20:17
    11560 20:21
    11554 20:09

    打印日志的字段数使用变量NF,最后一列数据使用变量$NF,倒数第二列使用$(NF-1)

    $ awk '{print NF, $NF,$(NF-1)}' log.csv
    

    针对uri请求, 只需要统计具体的文件,而不需要参数,可以使用split函数:

    $awk '{split($5, tmp, "?"); print tmp[1]}' log.csv   | sort | uniq -c | sort -nr | head
    

    04 伪装者

    知识星球.jpeg
    除了上面一些常用的统计与处理任务外,awk还支持从shell命令行接收参数,还可以用一维数组来模拟多维数组等等。

    也许你会认为awk比较难以调试,也许你会认为awk没有SQL的强大表现能力,也没有Python那么方便。但很多时候,awk会比Python快,awk自带很多的优化与异常处理,不用像在Python中那样遇到异常就报错的情况,我们姑且把awk当成数据分析的琅琊棒来使用吧!

    作为数据分析的常用命令行工具,awk还有一个版本,是GNU版本,叫gawk,主要是在awk基础上进行了很多扩展,比如一个简单的字符串长度统计功能,在MySQL中有两个函数,length()和char_length():

    select length('云戒云:yunjie-talk'), char_length('云戒云:yunjie-talk') from table limit 1;
    

    返回为21和15,前者会把一个中文当成三个字符,而后者会把一个中文当成一个。使用awk中的length和gawk中的length效果类似。

    上面虽然没有虽然介绍awk中的条件判断,但awk中,if条件与else也常常用到。不论你相似与否,awk已经基本上具有了编程语言的很多概念,所以常常也有人称它是:伪装成实用工具的一门编程语言。

    这本来就是一个伪装的世界,awk是伪装成实用工具的一门编程语言,Emacs是伪装成编辑器的操作系统。Python是伪装成脚本的数据分析通用编程语言,而我们是,伪装成……的……。

    相关文章

      网友评论

        本文标题:0x0A 数据琅琊棒,伪装者AWK

        本文链接:https://www.haomeiwen.com/subject/ebbihttx.html