awk 入坑指北
awk(/ɔːk/) 是 *nix 下一种强大的文本处理工具,其名称取自三位作者 Alfred Aho,Peter Jay Weinberger,Brian Wilson Kernighan。awk 提供的功能包括不仅限于正则匹配、流控制、算术运算、甚至于函数等编程语言具备的一些特性。它发行于 1977 年,已经超过了 40 岁堪称古董级软件。为了更让人能直接明白它的用途,我把它称为是命令行下的 Excel,其中的一些概念和 Excel 有很多相似之处。
TR;DR
- awk 是一种高效的文本处理工具。
- awk 脚本的基本结构 BEGIN -> BODY -> END。
- 基本语法,awk 脚本语法和 C 语言很很多相似之处。
- awk 脚本编程实践以及需要注意的地方。
基本用法
在 linux 环境下我们有一些文本处理需求时,awk 就能派上用场了,比如 nginx 的访问日志,文本信息去重等等。awk 可以直接在命令行中执行比如:
1 | echo "" | awk '{print "hello world!"}' |
也可以将一些逻辑比较复杂的代码写到一个 awk 脚本中,然后指定脚本文件执行:
1 | awk -f a.awk test.txt |
程序结构
awk 直接在命令行中输入和执行 awk 脚本效果是一样的,所以以下代码为了便于阅读都写入到一个脚本文件中。
一个完整的 awk 脚本分为三个部分:
1 | BEGIN{ print("BEGIN"); } |
但是 awk 脚本要能正确执行只需要其中一个阶段就行,第一个阶段是 BEGIN,就是还未开始扫描输入文本时候的预处理时间,中间 BODY 是扫描文本执行阶段,awk 每扫描到输入文本一行数据就会执行 BODY 中的脚本代码,最后是 END,即文本扫描完成的阶段,在绝大部分使用场景中我们直接在 {} 中写代码就可以了,即省略掉了 BEGIN 和 END。
awk 理解输入
前面已经提到,我将 awk 视为 *nix 下的 Excel,下面提到的一些概念和 Excel 颇为相似。对于 awk 处理的文本一般情况下是一行一行的,比如 nginx 的日志文件,在 awk 的视角文本的一行被视为一条记录(Record)行以 \n 来进行划分。在一行中通过空格又被分为多个域(Field),这就和 Excel 的行列差不多了。所以在 awk 程序中存在 2 个全局变量 NF,NR,这就很容易理解了。
需要值得注意的是域的索引不是从 0 开始的,而是从 1 开始,0 是当前行的引用,通过 $n 的语法来拿到不同域的值。
1 | { |
以上代码中 print 是 awk 的一个内置函数,用于输出文本信息。在 awk 脚本中可以通过 # 号来写注释。
awk 语法
和很多脚本程序一样,awk 没有严格的数据类型,不同数据类型直接可以直接转换。在 awk 中声明的变量统统会成为全局变量,所以在一处修改了变量值,脚本其他地方也会受到影响。在流程控制上几乎和主流编程语言完全一样。if-else, while 都是支持的,在后续的列子中可以看到。
传入参数
在命令行下通过 -v 参数还可以给 awk 脚本传入参数,比如:
1 | echo '' | awk -v name="jiavan" '{print("hello, "name);}' |
内置函数
awk 内置了很多字符串处理以及数学运算方面的函数,常用的如:
- index(str1, str2):返回 str2 在 str1 中出现的索引。
- length(str):返回一个字符串的长度。
- substr(str, n, m):截取字符串 str 的子串。
- match(str, reg):正则匹配,返回第一次匹配索引。
…..
跟多使用可以 man 一下。
内置变量
awk 还内置了一些变量名:
1 | $0 | 当前处理记录 |
awk 实践
文本去重
有以下具有重复文本的文件 name.txt。
1 | // name.txt |
上方 a.awk 先遍历文件行存入一个数组,在 awk 中数组的 key 可以是任意数据类型,value 也可以是任意数据类型,名称每出现一次 +1,最后就能统计出每个名称出现的次数以及将所有不重复的 key 输出到一个文件中,这里的操作和 bash 类似。
搜寻字符串
对于输入的文本 words.txt,我们使用 awk 找出带有 av
关键字的单词。
1 | // words.txt |
所以在 TX 游戏中我的 ID 是 Ji**an
这样显示的 :-)
本文仅提供给正在拉屎的人阅读,不做参考。
原文来自 https://jiavan.com
awk 入坑指北