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(高效大数据处理能力)之间的选择,兼顾便捷与效率!
还不想学~那就现实一点而!
曾经亲身参与京东NLP算法实习生面试、百度NLP算法实习生面试,技术面试官直接问:有没有AWK的使用经验…
所以,面试官的需求就是求职者的最高追求目标!程序猿,这需求还是得尽量满足…搞起!
3.AWK的基本语法:
一条完整的AWK命令由一下几部分构成:
awk [options] 'Pattern{Action}' file
- awk :是AWK命令执行的关键字
- [options]: 是运行的一些参数项,可以省略。
- 'Pattern{Action}': 是命令主要部分,其中Action是核心操作,Parttern有时可以省略。
- file: 用于指定我们操作的格式化文本的名字,可以同时操作多个文件。
3.1 简单介绍{Action}部分
按照编程语言学习的惯例,先来一个AWK界的Hello Word程序:
我们就从使用一个{Action}操作开始,指定一个打印的操作:
awk '{print}' a.txt
下面我们进行一个具有实际使用价值的命令:
如果我们只想打印第2列的数据:
AWK是逐行处理格式化文本数据的,逐行的意思是,当AWK处理一个文本的时候,会一行一行的处理,处理完第一行再处理下一行,AWK默认是以换行符(回车键/ \n)标记一行的结束,新的一行的开始。
当我们不指定文本内容的分割符的时候,awk默认把每一行的文本内容按照空格进行划分为列(当存在多个连续的空格时当做一个分割)。
注意:AWK的第一列是从下标1开始指定的,1代表当前行的第1个列数据,而0是内置的变量,表示整行的内容.
我们构建一个格式化的txt文本,内容如下:
我们可以输出文本的第一列、第二列数据:
针对某些列存在字段的缺失,AWK并不会报错,而是输出空值。
我们可以给每一行的数据添加上一些字符串信息到制定的位置:
awk '{print "IP统计>",1,"数量:",3}' test.txt
可知,在{Action}字段内,使用双引号包裹的信息,会被当做字符串输出。
3.2 简单介绍Pattern部分
前面我们只是简单的介绍了{Action},下面我们简单的了解一下Pattern,也就是模式。这里我先绍两个些比较特殊的模式:BEGIN与END
BEGIN模式:指定处理文本之前需要执行的操作
END模式:指定了处理文本之后需要执行的操作
awk 'BEGIN{print "IP地址","端口号”}’ test.txt
awk会首先指定BEGIN模式指定的命令,打印两个字符串,并不会操作test.txt文件。
awk 'BEGIN{print "IP地址","端口号"}{print 1,2}' test.txt
BEGIN模式指定的命令,在开始处理文本内容之前执行,一次类推,在处理完文本美容之后,指定END模式指定的命令。
awk '{print 1,2}END{print "IP地址","端口号"}’ test.txt
awk 'BEGIN{print "IP地址","端口号"}{print 1,2}END{print “IP地址1",”端口号1"}' test.txt
可以同时处理文本的头、尾内容。
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 -v FS='#' '{print 1,3}’ 1test.txt
同理我们可以使用-v OFS="||"参数选项英语用于指定文本的分隔符。
awk -v FS="#" -v OFS="||" '{print 1,3}' 1test.txt
再次说明一下AWK命令的形式:
awk [options] 'Pattern{Action}' file
-F用于指定输入的分隔符你、-V用于设置变量,都属于[Options]的一种。
至此,我们已经简单的介绍了[options] 'Pattern{Action}' 三部分了,已经可以简单的使用AWK了。
3.4 简单介绍一下AWK中的变量
接下来了解一下AWK的变量:
AWK中的变量,可以分为“内置变量”、“自定义变量”两种,其中输入分隔符、输出分隔符都属于内置的变量。
内置变量:就是在AWK中预先定义好的、内置为AWK内部的变量。
自定义变量:就是用户定义的变量。
例如:NR,用来表示每一行的行号,可以在输出文本的时候显示行号:
NF变量则记录了每一行一共有多少列:
此时,打印的每一行首尾的数字是对应的行一共有几列。
3.5 使用终端输出作为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也是可以编程的奥!!
完成一个带有if-else判断的脚本:
使用 Shell 引用:
让我们用一个示例来演示如何在一条 awk 命令中使用 shell 引用来替代一个 shell 变量。在该示例中,我们希望在文件 /etc/passwd 中搜索一个用户名,过滤并输出用户的账户信息。
AWK脚本3awk.sh的内容:
#!/bin/bash
### 读取用户名
read -p "请输入用户名:" username
### 在 /etc/passwd 中搜索用户名,然后在屏幕上输出详细信息
cat /etc/passwd | awk "/$username/ "' { print $0 }’
使用 awk 进行变量赋值
也可以通过定义AWK自变量的方式实现上面的功能:
注意:
分析一下 awk 脚本' $0 ~ name {print $0}'
中的$0 ~ name
。value ~ pattern
便是比较运算符之一,它是指:如果value(匹配的内容区域)
匹配了pattern(需要被匹配的内容)
则返回true
。进而该部分通过匹配的行信息会在{Action}命令中继续进行处理。
Next命令
next
命令在编写高效的命令脚本时候是非常重要的,它可以提高脚本速度
awk '3 > 10 { print0,"大于10" ; next; } 3<10 { print0,"小于10"} ' test.txt
当输入行用命令'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