前言概述基础语法脚本语法命令行语法程序结构操作符流程控制循环内建变量内建函数自定义函数常用场景示例快速帮助前言由于最近的工作内容的关系, 经常需要对文本文件做一些处理. 每次都要写个脚本来处理实在是有
前言
由于最近的工作内容的关系, 经常需要对文本文件做一些处理. 每次都要写个脚本来处理实在是有点麻烦. 这时候想起来很久以前稍微接触过的AWK, 来做这个工作真的是再合适不过了.
因此, 趁着这个机会, 把AWK深入学习一点,记录在此.
概述
AWK是一门解释型的编程语言。在文本处理领域它是非常强大的,它的名字来源于它的三位作者的姓氏:Alfred Aho, Peter Weinberger 和 Brian Kernighan。
GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK。
awk在下列任务中都有非常不错的发挥, 本文后续也会举很多示例.
- 文本处理
- 输出格式化的文本报表
- 执行算数运算
- 执行字符串操作等等
简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
你可以将其理解为一个linux命令,只是使用参数以及方法多样一些. 因为我们经常会在命令行直接使用它.
你也可以将其理解为一个简易的脚本语言, 因为在使用过程中我们也可以写逻辑表达式等各种语句.
先来个热场的示例.
已有一个文本文件,格式如下:
前面的数字是热度, 后面的字符串是搜索词.
100 阿里巴巴200 京东300 淘宝400 awk怎么使用
我们想计算, 热度大于等300的词的热度, 在总热度中的一个比例
虽然听起来有点绕, 但是这是一个非常常见的需求, 对应到这个示例中我们是想计算 (300 + 400 ) / ( 100 + 200 + 300 + 400), 此时我们只能打开我们的编译器, 选择一门语言之后开始写代码了. 其实不用.
把上面的文本内容放进 a.txt中,然后执行下面的shell命令即可, 你会看到预期之中的 0.7.
awk '{{if ($1 >= 300) {sub_sum +=$1}};sum += $1 }; END{ret = sub_sum * 1.0 / sum; print ret}' a.txt
这段脚本做了什么事情呢?
- 遍历每一行,按照空格为分隔符切割.
- 维护两个变量, 每一行都将第一列的数字累加到sum. 如果数字大于等于300,则将他累加到 sub_sum.
- 在执行结束后, 将 sub_sum和sum做一个除法.
怎么样, 是不是比写其他shell或者python脚本快多了?
接下来将进入学习时间, 我们逐个知识点的学习,看完本文,你也能这么花里胡哨的解决文本处理问题~.
基础语法
脚本语法
awk除了可以在命令行执行之外, 还可以写成脚本文件进行执行.我们大致的了解一下这个用法,之后不做详细讲解,以命令行用法为主要内容. 因为文本的用户和命令行大同小异.
首先,创建一个包含脚本内容的文本文件 test.awk
{print $1 }
然后我们用命令行执行这个脚本文件.
awk -f command.awk marks.txt
这个其实是相当于命令行直接执行的一个扩展, 当你写的脚本十分复杂(不推荐),且需要多人合作或者共享的时候, 脚本文件会是一个不错的选择.
命令行语法
awk [options] file ...
把上面脚本文件语法中的内容写到 options 即可.
上面所讲的, 是 awk是什么以及 怎么在系统中使用awk,接下来的内容就是 awk自身的一些语法.
程序结构
awk程序的思路是, 逐行处理一个文件.
那么让我们想一下, 当我们想要 处理一个文件的时候会需要做些什么?
- 进行处理之前, 先初始化一些信息.
- 逐行处理文本, 记录一些信息.
- 处理完之后,进行一些信息整理.比如打印,重定向等.
awk的程序结构也是如此.
BEGIN 语句块
BEGIN {awk-commands}
BEGIN语句块在程序开始的使用执行,它只执行一次,在这里可以初始化变量。BEGIN是AWK的关键字,因此它必须为大写,注意,这个语句块是可选的。
BODY 语句块
/pattern/ {awk-commands}
BODY语句块中的命令会对输入的每一行执行,我们也可以通过提供模式来控制这种行为。注意,BODY语句块没有关键字。
END 语句块
END {awk-commands}
END语句块在程序的最后执行,END是AWK的关键字,因此必须为大写,它也是可选的。
所以一个添加了全部可选项的awk命令如下所示:
awk [options] 'BEGIN{};{};END{}' file.txt
操作符
awk对常用的操作符都有支持,且与c语言使用方法一样.具体支持的操作符有:
- 算数操作符
- 增减运算符
- 自增自减操作符
- 赋值操作符
- 关系操作符
- 逻辑操作符
- 三元操作符
- 一元操作符
- 指数操作符
- 字符串连接操作符
- 正则表达式操作符
流程控制
awk支持流程控制, 比如在本文最前方的示例中我们使用了if语句.
或者类似下面的if语句都是合法的.
awk 'BEGIN { a = 30; if (a==10) print "a = 10"; else if (a == 20) print "a = 20"; else if (a == 30) print "a = 30";}'
循环
循环操作与其他C系语言一样,主要包括 for,whlie,do...while,break,continue 语句.
示例:
awk 'BEGIN { sum = 0; for (i = 0; i < 20; ++i) { sum += i; if (sum > 50) exit(10); else print "Sum =", sum } }
内建变量
- 0 表示正在处理的当前行
- 1 表示当前行的第一列, 以此类推, 2表示第二列...
- NR 表示文件中的行号,表示当前是第几行
- NF 表示文件中的当前行被分割的列数,可以理解为 MySQL 数据表里面每一条记录有多少个字段,所以 NF 表示倒数第一格字段, (NF-1) 表示倒数第二个字段.
- FS 表示 awk 的输入分隔符,默认分隔符为空格和制表符,可以对其进行自定义设置
- OFS 表示 awk 的输出分隔符,默认为空格,也可以对其进行自定义设置
- FILENAME 表示当前文件的文件名称,如果同时处理多个文件,它也表示当前文件名称
- RS 行分隔符,用于分割行,默认为换行符
- ORS 输出记录的分隔符,默认为换行符
内建函数
与内建变量相对应的, 也有一部分的内建函数.
awk 还提供了一些内置函数,比如:
- toupper() 用于将字符转为大写
- tolower() 将字符转为小写
- length() 长度
- substr() 子字符串
- sin() 正弦
- cos() 余弦
- sqrt() 平方根
- rand() 随机数
内建函数还有一些其他的, 具体可以在使用时在 man awk
中查询.
自定义函数
虽然我个人是不支持用awk来做这么繁杂的编程工作的,但是awk支持我们自定义函数并且调用. 语法规范如下:
function function_name(argument1, argument2, ...) { function body}
我们可以在一个awk脚本中放入一下内容, 然后执行它.
function main(){ print "function"}BEGIN { main()}
常用场景示例
这里会列出一些常用的,简单的使用示例.
所有的示例都以下面的示例为输入进行运行.
1) Amit Physics 802) Rahul Maths 903) Shyam Biology 874) Kedar English 855) Hari History 89
打印某列或者字段
AWK可以只打印输入字段中的某些列。
$ awk '{print $3 "/t" $4}' marks.txtPhysics 80Maths 90Biology 87English 85History 89
在示例文本中,第三列包含了科目名,第四列则是得分,上面的例子中,我们只打印出了这两列,$3 和 $4 代表了输入记录中的第三和第四个字段。
打印所有的行
默认情况下,AWK会打印出所有匹配模式的行
$ awk '/a/ {print $0}' marks.txt2) Rahul Maths 903) Shyam Biology 874) Kedar English 855) Hari History 89
上述命令会判断每一行中是否包含a,如果包含则打印该行,如果BODY部分缺失则默认会执行打印,因此,上述命令和下面这个是等价的
$ awk '/a/' marks.txt
打印匹配模式的列
当模式匹配成功时,默认情况下AWK会打印该行,但是也可以让它只打印指定的字段。例如,下面的例子中,只会打印出匹配模式的第三和第四个字段。
$ awk '/a/ {print $3 "/t" $4}' marks.txtMaths 90Biology 87English 85History 89
任意顺序打印列
$ awk '/a/ {print $4 "/t" $3}' marks.txt90 Maths87 Biology85 English89 History
统计匹配模式的行数
$ awk '/a/{++cnt} END {print "Count = ", cnt}' marks.txtCount = 4
打印超过18个字符的行
$ awk 'length($0) > 18' marks.txt3) Shyam Biology 874) Kedar English 85
查找history历史中,最常用的10个命令
history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head
过滤文件中重复行
awk '!x[$0]++' <file>
将一行长度超过 72 字符的行打印
awk 'length>72' file
查看最近哪些用户使用系统
last | grep -v "^$" | awk '{ print $1 }' | sort -nr | uniq -c
计算文本中的数值的和
awk '{s+=$1} ENG {printf "%.0f", s}' /path/to/file
快速帮助
当你用的时候临时有忘记的或者不确定的,随时可以查看帮助命令.
man awk
参考文章
完。
ChangeLog
2019-12-05 完成以上皆为个人所思所得,如有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文链接。
联系邮箱:[email protected]
更多学习笔记见个人博客或关注微信公众号 <呼延十 >------>呼延十
.
- 0