简明AWK实战教程

什么编程语言的教程这么贵?

1. 什么是AWK?

AWK是一个强大的格式化文本处理工具,一般在类Unix操作系统中都是必带的工具(Linux、Mac OS),因此,使用无需安装,非常的方便与便捷。

AWK其实是一种类似于shell的脚本编程语言,它支持基本的循环、遍历、判断等基本的功能,因此,你也可以像写shell脚本一样写AWK脚本,AWK也可以被理解为是一种脚本语言的解释器。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。为了掌握AWK的使用,必须掌握一些基本的AWK操作的语法。

2. 为什么学习AWK?

AWK与Grep、Sed并称为linux中的“三剑客”!

三剑客的特点:
grep:适合用于单纯的查找与匹配。
sed:适用于编辑匹配的文本。
AWK:适合处理格式化的文本,对文本进行复杂的格式化处理。

你可能会问:平常我一般会用python处理格式化文本啊,为啥还学AWK?

Maybe,针对一些大的txt文档,两者的执行效率不在一个数量级上….

我认为AWK工具,针对较大的格式化文本数据,可能是介于pandas(便捷)与Spark(高效大数据处理能力)之间的选择,兼顾便捷与效率!

一般AWK的效率优于Python

还不想学~那就现实一点而!

曾经亲身参与京东NLP算法实习生面试、百度NLP算法实习生面试,技术面试官直接问:有没有AWK的使用经验…

JD算法工程师招聘

所以,面试官的需求就是求职者的最高追求目标!程序猿,这需求还是得尽量满足…搞起!


3.AWK的基本语法:

一条完整的AWK命令由一下几部分构成:

awk [options] 'Pattern{Action}' file

  1. awk :是AWK命令执行的关键字
  2. [options]: 是运行的一些参数项,可以省略。
  3. 'Pattern{Action}': 是命令主要部分,其中Action是核心操作,Parttern有时可以省略。
  4. file: 用于指定我们操作的格式化文本的名字,可以同时操作多个文件。

3.1 简单介绍{Action}部分

按照编程语言学习的惯例,先来一个AWK界的Hello Word程序:
我们就从使用一个{Action}操作开始,指定一个打印的操作:

awk '{print}' a.txt

AWK输出文本中的内容

下面我们进行一个具有实际使用价值的命令:

df命令

如果我们只想打印第2列的数据:

AWK输出指定列的内容

AWK是逐行处理格式化文本数据的,逐行的意思是,当AWK处理一个文本的时候,会一行一行的处理,处理完第一行再处理下一行,AWK默认是以换行符(回车键/ \n)标记一行的结束,新的一行的开始。

当我们不指定文本内容的分割符的时候,awk默认把每一行的文本内容按照空格进行划分为列(当存在多个连续的空格时当做一个分割)。

注意:AWK的第一列是从下标1开始指定的,1代表当前行的第1个列数据,而0是内置的变量,表示整行的内容.

我们构建一个格式化的txt文本,内容如下:

文本内容

我们可以输出文本的第一列、第二列数据:

AWK输出指定列内容

针对某些列存在字段的缺失,AWK并不会报错,而是输出空值。

我们可以给每一行的数据添加上一些字符串信息到制定的位置:

AWK添加字符串输出

awk '{print "IP统计>",1,"数量:",3}' test.txt

可知,在{Action}字段内,使用双引号包裹的信息,会被当做字符串输出。

AWK添加字符串输出

3.2 简单介绍Pattern部分

前面我们只是简单的介绍了{Action},下面我们简单的了解一下Pattern,也就是模式。这里我先绍两个些比较特殊的模式:BEGIN与END

BEGIN模式:指定处理文本之前需要执行的操作
END模式:指定了处理文本之后需要执行的操作

awk 'BEGIN{print "IP地址","端口号”}’ test.txt

BEGIN模式

awk会首先指定BEGIN模式指定的命令,打印两个字符串,并不会操作test.txt文件。

awk 'BEGIN{print "IP地址","端口号"}{print 1,2}' test.txt

BEGIN模式

BEGIN模式指定的命令,在开始处理文本内容之前执行,一次类推,在处理完文本美容之后,指定END模式指定的命令。

awk '{print 1,2}END{print "IP地址","端口号"}’ test.txt

END模式

awk 'BEGIN{print "IP地址","端口号"}{print 1,2}END{print “IP地址1",”端口号1"}' test.txt

BEGIN+END模式

可以同时处理文本的头、尾内容。

3.3简单介绍Option部分

上面我们学习了AWK中的'Pattern{Action}'部分,下面我们学习一下Option部分,即AWK命令的参数项。

上面我们提到了AWK可以指定分隔符,默认的额分隔符是“空格”,其实分隔符也分为两类:输入分隔符、输出分隔符。

输入分隔符:FS,用于指定输入的格式文本时,按照何种分隔符进行列的划分。
输出分隔符:OFS,用于输出格式文本的时候,用何种分隔符进行列的划分。

格式化文本数据

awk -F# '{print 1,3}’ 1test.txt
awk -F "[\t]" '{print $1}' aa.txt //指定以tab为每行的分隔符

用-F参数项指定已#为列的分隔符。

AWK按照指定分隔符进行列的划分

还有另外一种方式可以用于指定输入的分隔符:

awk -v FS='#' '{print 1,3}’ 1test.txt

AWK按照指定分隔符进行列的划分

同理我们可以使用-v OFS="||"参数选项英语用于指定文本的分隔符。

awk -v FS="#" -v OFS="||" '{print 1,3}' 1test.txt

AWK按照指定分隔符分割列并按照指定输出分隔符输出

再次说明一下AWK命令的形式:

awk [options] 'Pattern{Action}' file

-F用于指定输入的分隔符你、-V用于设置变量,都属于[Options]的一种。

至此,我们已经简单的介绍了[options] 'Pattern{Action}' 三部分了,已经可以简单的使用AWK了。

3.4 简单介绍一下AWK中的变量

接下来了解一下AWK的变量:

AWK中的变量,可以分为“内置变量”、“自定义变量”两种,其中输入分隔符、输出分隔符都属于内置的变量。

内置变量:就是在AWK中预先定义好的、内置为AWK内部的变量。

自定义变量:就是用户定义的变量。

AWK的常用内置变量

例如:NR,用来表示每一行的行号,可以在输出文本的时候显示行号:

NR:显示每一行的行号

NF变量则记录了每一行一共有多少列:

NF:统计显示每一行有多少列

此时,打印的每一行首尾的数字是对应的行一共有几列。

3.5 使用终端输出作为AWK的输入

除了使用AWK可以操作本机的文本数据之外,还可以直接处理其它命令行命令的输出流。

通过使用管道命令 | ,可以直接上上一个命令的输出作为AWK数据的输入。

AWK通过管道命令处理终端的输出流

在上面的命令中,使用$3=="root" 表达式实现字符的匹配。

==实现字段完全匹配

~ /匹配字符/ 的比较操作,来模糊匹配第9列中存在sh字符串的行。

~实现字段的模糊匹配

~ /匹配字符/中,匹配字符还要注意关键字的转义。

针对复杂字符串的处理,需要使用复合表达式:

例如:

# awk '($3 ~ /^\$[2-9][0-9]*\.[0-9][0-9]$/) && ($4=="Tech") { printf "%s\t%s\n",$0,"*"; } ' tecmint_deals.txt

含义说明:

  • 表达式 1:($3 ~ /^\$[2-9][0-9]*\.[0-9][0-9]$/) ;查找交易价格超过 $20 的行,即只有当 $3 也就是价格满足 /^\$[2-9][0-9]*\.[0-9][0-9]$/ 时值才为真值。
  • 表达式 2:($4 == “Tech”) ;查找是否有种类为 “Tech”的交易,即只有当 $4 等于 “Tech” 时值才为真值。 切记,只有当 && 操作符的两端状态,也就是两个表达式都是真值的情况下,这一行才会被打上 (*) 标志。

3.6 写简单的AWK脚本

我的Mac系统里面AWK的安装目录在/usr/bin/awk下面,我们现在尝试像写shell脚本那样写一个简单的AWK脚本:

AWK脚本

所以,AWK也是可以编程的奥!!

完成一个带有if-else判断的脚本:

带判断的AWK脚本
使用 Shell 引用:

让我们用一个示例来演示如何在一条 awk 命令中使用 shell 引用来替代一个 shell 变量。在该示例中,我们希望在文件 /etc/passwd 中搜索一个用户名,过滤并输出用户的账户信息。

AWK脚本3awk.sh的内容:
#!/bin/bash

### 读取用户名

read -p "请输入用户名:" username

### 在 /etc/passwd 中搜索用户名,然后在屏幕上输出详细信息

cat /etc/passwd | awk "/$username/ "' { print $0 }’
使用Shell变量
使用 awk 进行变量赋值

也可以通过定义AWK自变量的方式实现上面的功能:

使用AWK自变量

注意:
分析一下 awk 脚本 ' $0 ~ name {print $0}' 中的 $0 ~ namevalue ~ pattern 便是比较运算符之一,它是指:如果 value(匹配的内容区域) 匹配了 pattern(需要被匹配的内容) 则返回 true。进而该部分通过匹配的行信息会在{Action}命令中继续进行处理。

Next命令

next命令在编写高效的命令脚本时候是非常重要的,它可以提高脚本速度

awk '3 > 10 { print0,"大于10" ; next; } 3<10 { print0,"小于10"} ' test.txt

Next命令

当输入行用命令'3 > 10 { print0,"大于10" ; next; } 打印以后,next命令将跳过第二个3<10 { print0,"小于10"}表达式的判断,继续判断下一个输入行,而不是浪费时间继续判断一下是不是当前输入行还小于10。

*AWK统计文件中某关键词出现次数

1、统计文件test.txt中第2列不同值出现的次数

awk '{sum[$2]+=1}END{for(i in sum)print i"\t"sum[i]}'  test.txt

如文件test.txt第2列的值为"00""01"或"02",执行结果如下:

[root@localhost cc]# cat test.txt
a 00
b 01
c 00
d 02
[root@localhost cc]# awk '{sum[$2]+=1}END{for(i in sum)print i"\t"sum[i]}' test.txt
00 2
01 1
02 1
[root@localhost cc]#

2、如只统计文件test.txt中第2列"00"或"01"出现的次数,命令可写为

awk '{if($2=="00") ++sum1;if($7=="01") ++sum2}END{print "00""\t"sum1"\n""01""\t"sum2}' test.txt

执行结果如下:

[root@localhost cc]# awk '{if($2=="00") ++sum1;if($2=="01") ++sum2}END{print "00""\t"sum1"\n""01""\t"sum2}' test.txt
00 2
01 1

4. 总结

以上只是简单的介绍了AWK的使用,这只是AWK强大功能的冰山一角,更详细的教程推荐!AWK在工业界的处理格式化文本数据的场景中具有广泛的使用,尤其是NLP相关的算法工程师,针对线上的大数据我们可能直接借助公司的Spark数据平台来处理,但针对线下的一些较大的格式化文本数据,AWK脚本语言或许是一个不错的选择!

推荐参考:

Linux 三剑客:

  • sed命令参考:http://man.linuxde.net/sed
  • grep命令参考:http://man.linuxde.net/grep
  • AWK命令参考:http://man.linuxde.net/awk

你可能感兴趣的:(简明AWK实战教程)