龙空技术网

使用AWK进行数据分析

自然之缠 192

前言:

如今兄弟们对“python 执行cmd命令 支持awk”大体比较重视,看官们都需要分析一些“python 执行cmd命令 支持awk”的相关资讯。那么小编也在网上汇集了一些有关“python 执行cmd命令 支持awk””的相关资讯,希望兄弟们能喜欢,你们一起来学习一下吧!

00 开篇

本篇更完善的版本,请参考:《全栈数据之门》之 『快刀AWK,斩乱数据』篇。

在数据分析领域里面,每个人都有自己得心应手的工具,也许你的工具是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.*$/ # 组合(逻辑,正则)

第三种模式,是简单的逻辑相等判断,判断第一个字段是否等于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 伪装者

除了上面一些常用的统计与处理任务外,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,斩乱数据』篇。

标签: #python 执行cmd命令 支持awk