当前位置: 首页 > 后端技术 > Java

Linux三剑客Awk入门指南

时间:2023-04-01 18:02:55 Java

大家好。我是新都。距离上次发技术文章已经快一个半月了。原因是我最近真的非常非常的忙。上班,或者上班的路上,周末,只想发一篇想写很久的文章凑热闹,简单教大家awk命令行工具的使用。了解我的人都知道,我本来就是运维出身,在运维方面学的东西不多。一些命令行工具让小偷溜之大吉,awk就是其中之一。后来我转做开发后,凭借着对一些命令行工具的熟练使用,很快解决了很多小问题。命令行的便捷和高效也曾多次让我们的同事震惊。各种命令行工具和管道的结合可以非常快速地解决很多问题。这里我就不展开了。有兴趣的可以去看看我之前写的一篇博客里面的一些我经常用到的linux命令。而今天的主角是awk,一个强大的文本处理工具,我每天都会用它来进行数据的清洗、筛选、查看,甚至是一些简单的数据统计。毫不夸张地说,我用awk解决了一些别人需要几个小时甚至根本无法处理的任务。在旁人看来,完全就是黑魔法。所以你可能感觉不到,我举个具体的例子。之前有个同事需要把一个几千万行(大于500MB)的文本文件平分成两个文件。其实他是想把几千万用户随机分成两组,做一些对比实验。你会怎么办?事实上,我使用awk一行命令来完成它。我输入命令20秒,然后执行半分钟。catusers.txt|awk'NR%2==0{print$1}'>0.txtcatusers.txt|awk'NR%2==1{print$1}'>1.txt说这么多只是为了引出awk功能强大,那么awk到底是什么?很多初学者认为awk是一个文本处理工具。它与grep、sed并称为Linux文本的三剑客。其实awk不仅仅是一个文本处理工具,还是一种编程语言。awk只提供了很多用于文本处理的内置变量和函数(后面会详细介绍),使得它非常容易用于文本处理。接下来请跟着我由浅入深学习awk的使用。awk的基本用法是,awk+具体执行+文本文件,也可以从linux管道中读取内容,两种使用方法如下。awk程序文本文件cat文本文件|awk程序awk实际上是面向行的数据处理,也就是说它的指令会针对每一行数据执行一次,比如下面的例子cata.txt|awk'{print$1,$3}'以上命令是输出文件中所有行的第一列和第三列,下标从1开始,$0有特殊含义,指的是这一行的所有数据。默认情况下,awk使用空格或制表符来分隔列。有时文本文件不是用空格或制表符分隔,而是用特殊符号(如-)来分隔列。awk还提供了-F参数来指定分隔符。猫a.txt|awk-F'-''{print$1,$3}'内置变量awk非常擅长处理文本,其中一个原因是它提供了大量的内置变量,你可以很容易地获取一些信息关于文本内容,比如当前在哪一行(NR),这一行有多少列(NF),当前正在处理的文件名(FILENAME)是什么……下面只是其中的一部分列表。该行的第1-n列NF当前行有多少列NR为当前行,从1开始,RS输入的记录分隔符默认为换行符,OFS输出的字段分隔符也是空格默认,和ORS输出的记录分隔符,默认是换行符ARGIND当前处理文件的ARGV标识符。比如我要输出一个文本文件a.txt,格式为|,第一行有多少列,我可以这样写:cata.txt|awk-F'|''{printNR,NF}'我在我的博客中使用了《awk实现类sql的join操作》当多个内置变量完成了对多个文本的复杂处理,有兴趣的可以看看。多个文件的相似交集和差异集易于实现。内置函数awk除了内置变量外,还有很多内置的常用函数,这里不再赘述。具体可以参考https://www.runoob.com/w3cnote/awk-built-in-functions.html,awk内置函数主要分为以下几种:算术函数、字符串函数、时间函数、位操作函数和其他函数。这些内置函数可以完成大多数常见操作。如果这些内置函数还不够,就像我刚才说的,awk是一种编程语言,你可以实现任何你需要的功能。语法接下来,让我们介绍一下awk作为命令行之外的编程语言的基础知识。变量首先从变量开始。除了上面提到的内置变量,你还可以自己使用其他变量。awk和python语言是弱类型的,变量不用声明直接使用。比如你需要一个文本文件第二列的综合平均值,可以这样写。cata.txt|awk'{sum+=$2;cnt+=1}END{printsum,sum/cnt}'其中sum和cnt是我们自定义的变量,在使用的时候写起来很方便。除了简单的变量,awk还支持一些复杂的数据结构,比如map。这里我举个例子。比如我们有一组人上个月的体重记录,想知道这个月每个人的平均体重,数据如下,一共有三列,分别是name,date,weight。张三2021-10-0167.7李四2021-10-0183.9张三2021-10-0268.1李四2021-10-0285.0张三2021-10-0368.3张三2021-10-0167.9李四2021-10-0384.0...利用awk中的map,可以分别存储每个人的体重总和和数量cnt的总和,等到所有的数据都处理完,统一输出。具体代码如下:cata.txt|awk'{sum[$1]+=$3;cnt[$1]+=1}END{for(keyinsum){printkey,sum[key]/cnt[key]}}'大家根据上面的例子判断也注意到有时候你要用到一些判断条件。比如第一个文本拆分的例子,我根据行号的奇偶性将文件一分为二。这时候需要根据不同的括号号执行不同的逻辑,awk中的判断逻辑也很简单。awk'expr{statement}'#花括号中的statement代码块只有当expr为真时才会执行。像上面多次出现的END,表示只有处理完所有的行,才会执行下面的代码块。END对应的是BEGIN,对应的代码是在文件处理开始之前执行的,所以一般会做一些文件初始化工作。其他自定义判断也可以类似写法,也支持ifelse,写法如下:cata.txt|awk'{if(NR%2==1)printNR,$1;elseprintNR,$2}'#如果是奇数行,输出行号和第一列,否则输出行号和第二列循环awk也支持for和while循环,和for和while是一样的c语言中的循环,如下:for(initialisation;condition;increment/decrement)actionwhile(condition)action这里我以awk输出0-100之间的所有质数为例,把上面提到的循环和判断串起来,除了变量定义外,与C语言约定的基本相同。开始{我=2;while(i<100){isPrime=1;对于(j=2;j