awk学习笔记-阿里云开发者社区

开发者社区> redraiment> 正文

awk学习笔记

简介: 看完sed部分之后 花了几个晚上看完后面 awk 部分。awk 不同于 sed,它是一门模式匹配的程序设计语言。学习 sed 和 awk 时,正则表达式可能是一大障碍。但事有凑巧,去年我暑假我一个人出去散心时,顺带看完了《精通正则表达式(第三版)》,另外我还掌握一些 Bash、Perl 等脚步编程的经验,因此很快就能适应 awk 的风格。 写到此处,我突然联系到《倚天屠龙记》中的张无忌,他
+关注继续查看

看完sed部分之后

花了几个晚上看完后面 awk 部分。awk 不同于 sed,它是一门模式匹配的程序设计语言。学习 sed 和 awk 时,正则表达式可能是一大障碍。但事有凑巧,去年我暑假我一个人出去散心时,顺带看完了《精通正则表达式(第三版)》,另外我还掌握一些 Bash、Perl 等脚步编程的经验,因此很快就能适应 awk 的风格。

写到此处,我突然联系到《倚天屠龙记》中的张无忌,他经常说“我有九阳神功护体,学什么武功都很快”;那我们程序员也可以牛气地喊“我掌握了正则表达式,UNIX下工具上手都很快”,哈哈。

环境的问题

比起 sed,使用 awk 时让我有点小意外,哈哈。

、Debian 5.0 默认安装的 awk 是 mawk。我一开始以为是 GNU awk,直到测试“gensub”函数(gawk特有)时才发现不对,于是通过 CD 盘安装了 GNU awk。到目前为止,gawk 的最新版本是 3.1.7,但 Debian 5.0 的软件包中提供的是 v3.1.5。而 fedora 默认安装的是 gawk v3.1.5,另外我在 Windows 下也使用 gawk.exe v3.1.5。

、在上文《sed单行脚本学习笔记》中已经提到用模式“[ -~]”来匹配任意可打印字符,这个特性在 mawk 中也可使用。理论上在 GNU gawk 中不能使用,但在 Windows 平台下的 gawk 却也具备此特性。为保持脚本的可移植性,应该用“[:print:]”来代替。

、gawk 支持扩展的正则表达式,在文档中指出操作符“/B”可以匹配单词中字符与字符之间的空白位置。例如模式“//Bour/”可以匹配“course”,不能匹配“our”。但这一特性在 gawk v3.1.5 中实现有问题。

$ cat data
ABCDE
ABCD
ABC
AB
A
$ awk --version | head -1
GNU Awk 3.1.5
$ awk '{gsub(//B/,"-")}1' data
A-B-C-DE
A-B-CD
A-BC
A-B
A

如上所示,当单词长度大于二,在 gsub 中“/B”不能匹配最后一个空白位置。这个问题在 gawk v3.1.6 版本被修复。

$ gawk-3.1.6/gawk --version | head -1
GNU Awk 3.1.6
$ gawk-3.1.6/gawk '{gsub(//B/,"-")}1' data
A-B-C-D-E
A-B-C-D
A-B-C
A-B
A

这到底算不算 bug,也只有 gawk 的维护者说了算,哈哈。

awk单行脚本

较少的设施总能给人带来更多的快乐。awk 作为一门编程语言,它的能力比原作者预期的更多,一些 sed 很费劲要完成的事情它能轻易完成。这造成的结果是,在大多数情况下用 awk 完成任务后,不会像 sed 一样让你兴奋不已,因为杀鸡用了牛刀,显得理所当然。

另一方面,一门抽象的语言不仅拥有丰富的表达能力,也有更具可读性的语句,使得语句不会过分精练。同样是输出,awk 中是“print”、sed 中只需一个字符“p”。

综上原因,用 awk 来编写只要 65 个字符的单行脚本显得勉强,下面罗列《AWK单行脚本快速参考》中几段精练的脚本。

# 删除所有空白行 (类似于 "grep '.' ") awk NF

这段脚本使用了 awk 的隐含动作:“{print $0}”。awk 中只要当值为 0 或空("")时才为“False”,否则都是“True”,而 NF 只有在空行上才为 0。因此整个语句的意思就是“但当前行的字段数大于0时,显示该行”。

# 删除重复的、非连续的行 awk '! a[$0]++'

这段脚本同样使用了隐含的打印动作。awk 的数组是一种关联数组,允许用字符串或数值做下标(事实上数值会先根据 CONVFMT 规则来转换成字符串),因此所谓的数组其实更像是键/值映射。通过关联数组来记录每一行的出现次数,且仅在第一次出现时输出。

单行脚本中的错误

# 倒置每行并打印 awk '{for (i=NF; i>0; i--) printf("%s ",i);printf ("/n")}' file

其中“printf("%s",i)”应该是“printf("%s",$i)”。这是译文中的错误,原文中正确。

# 删除重复连续的行 (模拟 "uniq") awk 'a !~ $0; {a=$0}'

运算符“!~”为“不匹配”,运算符右边可以是 awk 中任意表达式,awk 将它作为一个字符串并用来指定一个正则表达式。由此,这段代码不能正确处理以下数据:

$ cat data
ABCDE
ABCD
ABC
AB
A
$ awk 'a !~ $0; {a=$0}' data
ABCDE

需要将匹配改成比较,即“awk 'a != $0; {a=$0}'”。


版权声明

请尊重原创作品。转载请保持文章完整性,并以超链接形式注明原始作者“redraiment”和主站点地址,方便其他朋友提问和指正。

联系方式

我的邮箱,欢迎来信(redraiment@gmail.com
我的Blogger(子清行):http://redraiment.blogspot.com/
我的Google Sites(子清行):https://sites.google.com/site/redraiment
我的CSDN博客(梦婷轩):http://blog.csdn.net/redraiment
我的百度空间(梦婷轩):http://hi.baidu.com/redraiment

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10080 0
Linux学习笔记
1.Linux约定俗成的拓展名: 2.系统分区——由硬盘结构决定的:   3.一切皆文件:(分区——格式化——挂载”可以当做盘符理解“)     4.文件系统 (Linux必须安排根分区和swap分区才能使用)5.
825 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
10883 0
+关注
redraiment
阿里巴巴-淘宝-新制造-高级技术专家,PostgreSQL、Clojure、FreeBSD等技术爱好者
110
文章
5
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载