Linux脚本攻略学习笔记14

来源:互联网 发布:什么是云计算和云服务 编辑:程序博客网 时间:2024/06/05 18:07

使用awk进行高级文本处理

awk 是一款设计用于数据流的工具。它颇为流行的原因在于可以对列和行进行操作。awk有很多内建的功能,比如数组,函数等,这是它和C语言的相同之处。

(1)预备知识

awk的脚本的结构基本如下所示:
$ awk 'BEGIN{print "start"} pattern {comands} END {print "end"}' file
awk命令也可以从stdin中读取。
awk脚本通常由3部分组成。BEGIN,END和带模式匹配选项的常见语句块。这3个部分都是可选项,在脚本中可以省略任意部分。

(2)实战演练

以下awk脚本被包含在单引号或双引号之间:
$ awk 'BEGIN {statement}{statements} END {end statements}'
也可以使用:
$awk "BEGIN {statements} {statements} END {end statments}"

例如:
$ awk  'BEGIN {i=0} {i++} END{print i}' filename
或者
$ awk "BEGIN {i=0}{i++} END {print i}" filename

(3)工作原理

awk命令的工作方式如下所注。
(1)执行BEGIN{ commands}语句块中的语句。
(2)从文本或stdin中读取一行,然后执行pattern{commands}. 重复这个过程,直到文件全部被读取完毕。
(3)当读至输入流末尾时,执行END{commands}语句块。
BEGIN 语句块在awk开始从输入流中读取行之前被执行。这是一个可选的语句块,诸如变量初始化,打印输出表格的表头等语句通常都可以写入BEGIN语句块中。
END语句块和BEGIN语句块类似。END语句块在awk从输入流中读取玩所有的行之后即被立即执行。像打印所有行的分析结果这类汇总信息,都是在END语句块中实现的常见任务(例如:在比较过所有的行之后,打印出最大数)。它也是一个可选的语句块。
最终要的部分就是pattern语句块中的通用命令。这个语句块同样是可选的,如果不提供该语句块,则默认执行{print},即打印所读取的每一行。awk对于每一行,都会执行这个语句块,这就像一个用来读取行的while循环,在循环体中提供了相应的语句。
没读取一行,awk就会检查该行和提供的样式是否匹配。样式本身可以是正则表达式,条件语句以及航匹配范围。如果当前行匹配该样式,则执行{}中的语句。
样式是可选的。如果没有提供样式,那么awk就认为所有的行都是匹配的,并执行{}中的语句。
来看例子:

(4)补充内容

awk命令具有丰富的特性。要想洞悉awk编程的精妙之处,首先应该熟悉awk重要的选项和功能,让我们来看看awk的一些重要特性。

(a):以下是一些用于awk的一些特殊变量。
NR:表示记录数量,在执行过程中对应于当前行号。
NF:表示字段数量,在执行过程中对于当前行的字段数。
$0:这个变量包含执行过程中当前行的文本内容。
$1:这个变量包含第一个字段的文本内容。
$2:这个变量包含第二个字段的文本内容。
例如:

我们可以用print $NF打印一行中的最后一个字段,用$(NF-1)打印倒数第二个字段,其他字段依次类推即可。

awk的printf()函数的语法和C语言中的同名函数一样,我们也可以使用这个函数来代替print。
再来看awk的一些基本用法,打印每一行的第2和第3个字段:
$awk '{print $2,$3}'  file

要统计文件的行数,使用下面的命令:
$awk 'END{print NR}' file
这里只使用了END语句块,每读入一行,awk会将NR更新为对应的行号。当到达最后一行时,NR中的值就是最后一行的行号了。

awk通常默认读取一个文件的所有行,如果只是想读特定行的内容,就可以使用getline函数,有时候,我们需要从BEGIN语句块中读取第一行。
语法:getline var。变量var就包含了特定行的内容。如果调用不带参数的getline,我们可以用$0,$1,$2访问文本文件的内容。
例如:


此外,我们还可以使用过滤模式对awk处理的行进行过滤例如
$ awk 'NR<5' # 行号小于5的行
$ awk 'NR==1,NR==4' # 行号在1到5之间的行
$ awk '/linux/' #包含样式的行(可以使用正则表达式来指定)
$ awk '!/linux/' # 不包含包含模式的为linux的行

(b) 设置字段界限符
默认的字段定界符是空格。我么也可以用-F “delimiter” 明确指定一个定界符:
$ awk -F: '{print $NF}' /etc/passwd
或者
$ awk 'BEGIN {FS=":"} {print $NF}' /etc/passwd

在BEGIN语句中则可以用FS=“delimiter” 设置输出字段的定界符。
(c) 在下面的代码中,echo 会生成一个空白行。变量cmdout包含命令grep root /etc/passwd的输出,该命令会打印出包含root的行。
将命令的输出结果读入变量output的语法如下:
$ "command" | getline output 
例如:
$ echo | awk '{"grep root /etc/passwd | getline cmdout; print cmdout"}'
通过使用getline,我们将外部shell命令的输出读入输入变量cmdout。

awk支持以文本作为索引的关联数组。

(d)在awk中使用循环
在awk中更可以使用for循环,其格式如下:
for(i=0;i<10;i++)  {print $i;}
或者
for(i in array) {print array[i]}