第6章 利用sed/awk处理文本
磨刀不误砍柴工,如果能妥当利用
sed
和awk
这两个利器,很多日常的命令操作和文件操作会事半功倍;当然用python的os、re模块配合也能实现这样的功能,但一来不方便,二来阅读很多bash脚本时会用到,三来毕竟是linux原生语言和工具,还是有必要学习的。想起来读的布莱恩的《Unix 传奇》中对awk以及很多小工具诞生经过的叙述,感觉那个时代(1960-70s)的技术人员真的是好纯粹,最初是因为MIT的计划失败后,At&T实验室1127中心的肯·汤普森等人还想搞操作系统,于是在只有500K磁盘的PDP-7上开始开发Unix系统。肯·汤普森为了读取磁盘上的信息开发了磁盘驱动、在同事的建议下斯图亚特发明了make提升编译效率、道格·麦克尔罗伊受到花园水管的启示发明了管道、本贾尼经常去办公室与它们探讨C++而道格提出了很多建设性意见、然后是各种文字处理工具(因为1127经常要打印文件)、编译器-编译器(如yacc)的发明(因为文字排版或是其它工作常常需要发明新的语言)……一切都是出自对探索技术的热爱和最原始的“想要做得更好”的朴素想法,多想我有一天也能体验这种纯粹的氛围呀
awk和sed都是基于stream的处理工具,这和Unix中管道的机制一脉相承。即:它们总是从输入流一行一行地读取,经过某种处理后一行一行地打印到输出流,且不再回头
区别在于sed一般用来做文本替换,awk一般用来做格式化输出?也不一定,区别慢慢体会
[TOC]
awk
基本语法
直接通过命令行
- 第一个参数是单引号括起来的pattern和action。注意pattern一定要用斜杠括起来。即:如果当前行的某些数据匹配此pattern(是基于正则的),则对当前行执行action,比如
print $0
就是打印当前行的第一列;至于怎么将一行分割成列,默认是空格,也可以指定为逗号(如处理csv文件)等,后面会讲。第二个参数是文件名,指定要处理的文件为输入流,也可以同时处理多个文件
|
|
通过脚本
- 提前将命令写在
hello.awk
中,执行
|
|
BEGIN块
awk允许在处理所有输入之前预先执行一段指令,这段指令需要被放在BEGIN块里;对偶的是END块,即处理完所有输入后执行的指令
|
|
print命令
示例文件
以下命令可以做到输出以Al
开头的行的第一个列的值(即国家名称)
|
|
当然,也可以不写pattern,这样会匹配所有行
|
|
printf指令
语法和C语言一样,不同的是没有括号
|
|
可以配合BEGIN块用printf来打印列名
指定分割符
正如前文所说,比如在处理内容本身可能带有空格的数据或者处理csv文件时,希望将分割符指定为逗号,只需通过-F
选项即可,注意分隔符要紧跟在-F
后面。注意不要与-f
混淆了,后者是指定程序所在文件
|
|
也可以通过FS变量指定(变量在下面讲)
|
|
一个有趣的例子
|
|
利用了正则表达式匹配
使用变量
和shell脚本中语法一样,比如之前的打印列名的程序可以更简洁,因为列的格式和下面数据格式是一样的,所以可以预先存储在变量中
|
|
控制语句
语法和C一样,但是好像因为不能加大括号,只能做一件事
- if
|
|
- for
|
|
- while
|
|
运算
完全和C一样,也支持自增自减,+=等
|
|
Sed
- TODO