Chinaunix首页 | 论坛 | 博客
  • 博客访问: 265868
  • 博文数量: 56
  • 博客积分: 1190
  • 博客等级: 少尉
  • 技术积分: 640
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-21 17:05
文章分类

全部博文(56)

文章存档

2014年(2)

2013年(4)

2012年(46)

2011年(4)

我的朋友

分类: LINUX

2012-04-05 16:57:37

Bash: awk
(2009-04-02 22:38:17)


术语:

FS-- 输入字段分隔符, 可以指定,如指定文件file中的分隔符为冒号:可以用 awk -F: '/Mary/{print $0}' file

OFS-- 输出字段分隔符, 默认为空格

$0--  一行记录

$1, $2 ...---一  记录中的字段

RS--输入记录的分隔符 (默认为换行符)

ORS--输出记录的分隔符  (默认为换行符)

NF-字段的数目

$NF--某行最后一个字段的值

命令行awk命令格式:

1) awk '/模式/ {操作; 操作}' filename

2) awk '/模式/ {操作; \

             操作}' filename

3) awk 'BEGIN { }/模式/{ 操作;操作 }END{  }' filename

注意:块之间不加;块内部语句之间可以加;块内部操作可以被{}括起来

awk脚本:

如果awk命令被写在文件里,就要用-f选项指定awk的文件名,后面再加上所要处理的输入文件的文件名。awk从缓冲区读入一条记录,接着测试awk文件中的每一条命令,然后对读入的记录执行命令。处理完第一条记录后, awk将其丢弃,接着将下一条记录读入缓冲区,依次处理所有记录。如果没有模式限制,默认的操作就是打印全部记录。而模式如果没有相应的操作,则默认行为是打印匹配它的记录。  

awk脚本格式:

脚本是一个包含awk注释和语句的文件。如果同一行中有多条语句或操作,必须用分号将他们分开。如果每条语句都在不同的行上,就不需要用分号来分隔。如果操作跟在某个模式后面,它的左花括号就必须与该模式位于同一行。注释要以#开头。

#Scriptname:

#Purpose:

BEGIN{

      。。。。。

}

/模式/{

操作1

操作2

}

END{

   。。。。

}

---------------------------------------------------------------------------------

1. 什么是awk?

 awk是一种用于处理数据和生成报告的UNIX编程语言。 awk可以在命令行进行一些简单的操作,也可以编成程序来处理较大的应用。shell程序通常使用awk来处理命令,它也是管理小型数据库不可或缺的工具.

2. awk命令的格式

awk有很多版本,包括:旧版awk, GNU awk(gawk), POSIX awk等。在大多数系统上,使用旧版本,输入awk,使用新版本输入nawk,GNU版输入gawk.

   (1)awk  ‘模式'   文件名: 执行结果是所有匹配该模式的行都显示在屏幕上

        如: awk  '/Mary/'   employess (如果文件employees中某行包含Mary,打印该行)

   (2)awk  ‘{ 操作 }'  文件名: 会对所有输入行执行指定操作。

        如: awk   '{print $1}'  employees (打印文件employees中每行的第一个字段)

   (3)awk  '模式 { 操作 } '  文件名 

awk以逐行方式扫描文件(或输入),以查找匹配某个特定模式的文本行,并对这些文本行执行(括在花括号中的)指定操作。 

        如: awk  '/Sally/{print $1, $2}' employees (如果文件employees中的某行包含Sally时,打印该行的头两个字段,字段之间的分隔符是空白符)

模式-----是由某种类型的表达式组成的语句。如果某个表达式中没有出现关键字if,但实际计算时却暗含if这个词,那么,这个表达式就是模式。模式不能括在大括号中,模式由括在连个正斜杠/ / 之间的正则表达式,一个或多个awk操作符组成的表达式组成。

操作-----由括在大括号内的一条或多条语句组成,语句之间用分号或换行符隔开。

 3.awk是如何工作的?

(1) awk使用一行作为输入(通过文件或管道),并将这一行赋给内部变量$0,默认时每一行也可以称为一个记录,以换行符结束。

(2) 行被空格分解成字段(单词),每一个字段存储在已编号的变量中,从$1开始可以多达100个字段。

(3) 执行模式匹配

(4) 执行花括号中的操作

(5) 输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。这个过程将持续到整个文件的所有行都处理完毕。

注意:awk如何知道输入中空格是用来分隔字段的呢?因为有另一个内部变量FS用来确定字段的分隔符。初始时,FS被赋为空格(包含制表符和空格符)。如果需要使用其他的字符分隔字段,如冒号或破折号,则需要将FS变量的值设为新的字段分隔符。  

4. awk命令的输入

   4.1 从文件输入

     如: awk  '/Mary/'   employess (如果文件employees中某行包含Mary,打印该行)

   4.2 将一条或多条命令的输出通过管道发给awk处理.

   格式: command | awk  '模式'

         command | awk  '{ 操作 }'

         command | awk  '模式 {操作} '

   如: rusers | awk  '/root$/{print $1}'

   rusers命令打印出有哪些用户登录在局域网的其他机器上。rusers的输出管道发送给awk,作为它的输入。如果输出中有某行以正则表达式root结尾,就打印该行的第一个字段,即root登录的所有机器名。

5. 记录与字段

在awk看来输入数据具有格式和结构,而不是无休止的字符串。默认情况下,每一行称为一条记录,以换行符结束。

5.1 记录分隔符(RS/ORS)

默认情况下,输入和输出记录的分隔符(行分隔符)都是回车符(换行符),分别保存在awk的内置变量ORS和RS中。 ORS和RS的值可以修改,但是只能以特定的方式进行修改。

5.2 变量$0

awk用$0指代整条记录(当$0因替换或赋值而改变时,NF的值,即字段的数目值也可能改变)。换行符的值保存在awk的内置变量RS中,默认为回车。

5.3 记录号(NR)

每条记录的记录号都保存在awk的内置变量NR中。每处理完一条记录,NR的值都会加1。

5.4 字段(Field)

每条记录都是由称为字段的词组成。默认情况下,字段间用空白符(即空格或制表符)分隔。每个这样的词 称为一个字段,awk在内置变量NF中保存记录的字段数。NF的值因行而异,其上限与具体的版本的实现相关,通常是每行最多100个字段。可以创建新的字 段。每条记录都是从第一个字段(用$1表示)开始,然后是第二条字段 ($2),依此类推。

5.5 输入字段分隔符(FS)

awk的内置变量FS中保存了输入字段分隔符的值。使用FS的默认值时,awk用空格或制表符来分隔字段,并且删除各字段前多余的空格或制表符。可以通过在BEGIN语句中或命令行上赋值来改变FS的值。

1)从命令行改变字段分隔符

用-F选项在命令行设置输入字段分隔符,当冒号紧跟在-F选项的后面时,awk就会在文件中查找冒号,用以分隔字段。

awk -F: '/Tom Jones/{print $1, $2}' employees

可以指定多个输入字段分隔符。如果有多个字符被用于字段分隔符FS,则FS对应是一个正则表达式字符串,并且被括在方括号中。

awk -F'[ :\t]' '{print $1, $2, $3}' employees (指定字段分隔符是空格,冒号或制表符)

2)在BEGIN语句中改变FS的值

5.6 输出字段分隔符(OFS)

   默认的输出字段分隔符是单个空格,被保存在awk的内置变量OFS中。无论OFS如何设置,print语句中用于分隔字段的逗号,在输出时都被转换成OFS的值。除非字段间有逗号分隔,否则输出结果的字段间不会加上OFS的值。另外,OFS的值可以改变。

6. BEGIN块

BEGIN后面跟了一个操作块。awk必须对输入文件进行任何处理之前先执行该操作块。实际上,不需要任何输入文件,也能对BEGIN块进行测试,BEGIN操作常被用于修改内置变量(OFS, RS, FS等)的值,为用户自定义变量赋初值和打印输出的页眉或标题。

   如:awk 'BEGIN{FS=":"; OFS="\t"; ORS="\n\n"}{print $1, $2, $3}' file

7. 模式(Pattern)

模式由正则表达式,判别条件真伪的表达式或二者的组合构成。awk的默认操作是打印所有使表达式结果为真的文本行。模式表达式中暗含着if语句。如果模式表达式含有if的意思,就不必用花括号把它括起来。当if显示得给出,这个表达式就成了操作语句,语法将不一样。

7.1 正则表达式(RE)

对awk而言,正则表达式是置于两个正斜杠之间,由字符组成的模式。如果输入行中的某个字符串与正则表达式匹配,则执行与该表达式关联的所有操作。如果没有指定操作,则打印正则表达式匹配的记录。

7.1.1 awk的正则表达式元字符   

(1)^ 在串首匹配   (2)$ 在串尾匹配  (3). 匹配单个任意字符  (4) * 匹配0个或多个前导字符

(5)+ 匹配1个或多个前导字符           (6)? 匹配0个或多个前导字符

(7)[ABC] 匹配指定字符组中任一字符    (8)[^ABC] 匹配任何一个不在指定字符组中的字符

(9)[A-Z] 匹配A到Z之间的任一字符      (10)A|B 匹配A或B

 (11)(AB)+ 匹配一个或多个AB的组合      (12) \* 匹配星号本身

(13)& 用在替代串中,代表查找串中匹配到的内容

7.1.2 awk不支持的元字符:\< \> ; \( \);  \{ \}                          

7.2 匹配整行

如果没有指定操作,则单个正则表达式将对整行进行模式匹配,并打印出所匹配的行。

可以使用元字符^来表示需要进行行首匹配的正则表达式。

7.3 匹配操作符

 ~ 用于对记录或字段的表达式进行匹配。

7.4 POSIX字符类

 括号类 含义 
 [:alnum:]  字母数字字符
 [:alpha:]  字母字符
 [:cntrl:]  控制字符
 [:digit:]  数字字符
 [:graph:]  非空白字符(非空格,控制字符等)
 [:lower:]  小写字母
 [:print:]  与[:graph:]相似,但是包含空格字符
 [:punct:]  标点字符
 [:space:]  所有的空白字符(换行符,空格,制表符)
 [:upper:]  大写字母
 [:xdigit:]  允许十六进制的数字(0-9a-fA-F)

7.5 比较表达式

    1)关系运算符

    <, <=, ==, !=, >=, >, ~(与正则表达式匹配), !~ (与正则表达式不匹配)

    awk  '$3 > 5000{ print $1 } ' employees

    awk  '$2 ~ /Adam/' employees (如果记录中的第2个字段匹配正则表达式Adam,那么打印该记录)

    awk  '$2 !~ /Adam/ ' employees (如果记录中的第2个字段不匹配正则表达式Adam,那么打印该记录)

    2)逻辑操作符和复合模式

    &&(逻辑与), ||(逻辑或), !(逻辑非) 

    awk '$2 > 5 && $2 <= 15' filename 

    awk '$3 == 100 || $4 > 50' filename

    awk '!($2 < 100 && $3 <20)' filename 

    3)范围模式

   范围模式先匹配从第一个模式的首次出现到第二个模式的首次出现之间的内容,然后匹配从第一个模式的下一次出现到第二个的下一次出现。

   awk '/Tom/,/Suzanne/' filename

   awk 将显示从Tom首次出现的行到Suzanne首次出现的行这个范围内的所有行,包括两个边界在内。如果没有找到Suzanne,awk将继续打印各行直到 文件末尾。如果打印完Tom到Suzanne的内容之后,又出现了Tom,awk就又一次开始显示行,直到找到下一个Suzanne或文件末尾。

 

8. 操作

操作是花括号中以分号隔开的语句。如果操作前面有个模式,则该模式控制执行操作的时间。操作可以是简单的语句或复杂的语句组。同一行内的多条语句由分号分隔,独占一行的语句则以换行符分割。

8.1 格式化输出

(1)print函数

 print 用于打印不需要特别编排格式的简单输出。更为复杂的格式编排要使用printf和sprintf函数。

 print函数的参数可以是变量,数值或字符串常量。字符串必须用""括起来。参数之间用,分隔,如果没有逗号,所有的参数就会被串在一起,逗号等价于OFS中的值,默认情况是空格。

 print函数的输出可以被重定向,也可以通过管道传给另一个程序。

 (2) OFMT变量

通过设置OFMT,打印数字的时候,可以控制数字的格式。OFMT的默认值是"%.6gd"表示只打印小数部分的前6位。如:awk 'BEGIN{OFMT="%.2f";print 1.2456789, 12E-2}' (设置了OFMT,在打印浮点数时,就只打印小数部分的前两位,%表示接下来要定义格式)

(3) printf函数

printf函数返回一个带格式的字符串给标准输出,printf不会行尾自动换行。因此,如果要换行,就必须在控制串中提供转义字符\n.每一个% 和格式说明都必须有一个对应的变量。要打印的%, 就必须在控制串中给出2个%

8.2 比较表达式

 1)条件表达式

    awk '{ max=($1 > $2) ? $1 :$2; print max }' filename

 2)算术运算

   awk '/southern/{ print $5 + 10.56 }' datafile

 3)赋值运算

   awk '/Derek/{$8 += 12; print $8}' datafile

8.3. 变量  

awk的变量不用申明其类型,只要在awk程序中被提到,变量就开始存在。

1)数值变量和字符串变量

变量可以是一个字符串或一个数字,也可以既是字符串又是数字。变量被设置后,就变成与等号右边那个表达式相同的类型。未经初始化的变量的值是0或者"",究竟是哪个取决于它们被使用时的上下文。

所有由split函数创建的字段或数组元素都被视为字符串,除非它们只包含数字值,如果某个字段或数组元素为空,它的值就是空串。空行也可以被视为空串。

name="Nancy" #name是字符串

x++ #x是数字,初始化为0,然后加1

将一个字符串强制转换为数字:name + 0

将数字转换成字符串:number " "

2)用户自定义变量

用户自定义变量的变量名可以由字母,数字和下划线组成,但不能以数字开头。awk的变量不用申明其类 型,awk可以从变量在表达式的上下文推导出它的数据类型。如果变量未被初始化,awk会将字符串变量初始化为空串,将数值变量初始化为0。必要 时,awk会将字符型变量转换为数值型变量,或者反向转换。对变量赋值要使用awk的赋值运算符 ( =, +=, -=, *=, /=, %=, ^= )

8.4. 条件语句

条件模式中的if是隐含的,而条件操作语句的if则是直接声明的,如果在条件表达式后面的语句不止一条,就要用; 或用换行符\把他们隔开,还要用{ }把这一组语句都括起来,以作为一个块来被执行。

awk '{ if ($6>50) { print $1 } } ' filename

awk '{ if($6 >5) { print $1 } else { print $2 } }' filename

awk ' { if($3 >89 && $3 <101) Agrade++ \

        else if($3 > 79) Bgrade++ \

        else if($3 > 69) Cgrade++ \

        else Fgrade++ } ' filename

8.5. 循环

通常被用来对记录中的每个字段重复执行某种操作,或者在END块中用来循环处理某个数组中的所有元素。

 1)while循环

    awk '{i=1; while(i<= NF) { print NF, $i; i++ }}' filename

 2) for 循环

     awk '{for( i=1; i<=NF; i++) print NF, $i }' filename

 3)循环控制: break和continue 

   break 将控制跳转到for循环体之后的语句

   continue使控制转转去执行for循环表达式的x++然后开始下一轮循环

8.6. 程序控制语句: next和exit  

next语句从输入文件中取出下一行输入,然后从awk脚本的顶部重新开始执行

exit语句用来终止awk程序,它只能中断对记录的处理,不能跳过END块,如果exit语句的参数是一个0~255之间的值,这个值就会被打印在命令行上,以表明程序是否执行成功,并且指出失败的类型。echo $?=0表明成功,非0表明失败,退出状态由程序员决定是否在程序中提供。

8.7. 数组

 数组在awk中称为关联数组(associative array),因为它的下标既可以是数字也可以是字符串。下标通常又被称作键,并且与对应的数组元素的值相关联。数组元素的键和值都存储在awk程序内部 的一个表中,该表采用的是散列算法。正是由于使用了散列算法,所以数组元素不是顺序存储的,如果将数组的内容显示出来,元素的排列顺序也许跟想象中不一 样。

数组元素也是被用到时才被创建,awk还能判定这个数组用于保存数字还是字符串。根据使用时的上下文环境,数组元素被初始化为数字0或空字符串。数组的大小不用申明。awk数组可用于从记录中收集信息,也可用于统计总数,计算词数,记录模式出现次数等应用。

8.7.1 关联数组的下标

 1)使用变量作为数组索引

 2)特殊for循环

 3)用字符串作为数组下标

 4)用字段值作为数组下标

 5)数组与split函数

 6)delete函数

 7)多维数组

8.7.2. 处理命令行参数

1) ARGV内置数组

   如:如果在命令行输入 awk -f awksript datafile "Peter Pan" 12

   -f选项和脚本名awksript 不被计算在ARGV数组,脚本awksript 如下

     #Scriptname:

     BEGIN{

      for( i = 0; i < ARGC; i++) {

 printf("argv[%d] is %s\n", i, ARGV[i])

 }

 printf("The number of arguments, ARGC=%d\n", ARGC)

}

输出为:argv[0] is awk

        argv[1] is datafile

        The number of arguments, ARGC=2

2) ARGC:是一个包含命令行参数个数的内置变量

8.8. awk的内置函数

8.8.1字符串函数

1)sub和gsub函数

2)index函数

3)length函数

4) substr函数

5)match函数

6)split函数

7)sprintf函数

8.9. 内置算术函数

8.9.1 整数函数

8.9.2 随机数发生器

8.10. 用户自定义函数

 

9. END块

END块不匹配任何输入行,而是执行任何与之关联的操作。awk处理完所有输入行之后才处理END模式。

如:awk '/Mary/{ count++ }END{ print "Mary was found" count "times."}' filename

 

10. 重定向

10.1 输出重定向  

将awk的输出重定向到linux文件时,会用到shell的重定向操作符。重定向的目标文件名必须用双引号括起来。如果使用的重定向操作符为>, 则文件被打开并清空。文件一旦打开,就会保持打开状态直到显示关闭或awk程序终止。此后print语句的输出都将追加到文件尾部。符号>>也用于打开文件,但是不清除文件内容,它只向文件追加内容。

  如: awk '$4 >= 70 { print $1, $2 > "passing file" }' filename (如果记录的第4个字段的值大于或等于70,它的头两个字段就被打印到文件passing_file中。)

10.2 输入重定向

函数getline用于从标准输入,管道或文件(非当前处理的文件)读取输入。 getline函数用于读取下一输入行,并且设置内置变量NF, NR和FNR.如果读到一条记录,函数就返回1,如果读到EOF(文件末尾)则返回0。如果发生错误,比如打开文件失败,则返回-1. 

 

11. 管道

如果在awk程序中打开了管道,就必须先关闭它才能打开另一个管道。管道符右边的命令被括在双引号之间。每次只能打开一个管道。

如果打算再次在awk程序中使用某个文件或管道进行读写,则可能要先关闭程序。因为其中的管道会保持打开状态直至脚本运行结束。注意,管道一旦被打开,就会保持打开状态直至awk退出。因此,END块中的语句也会受管道的影响。

阅读(1873) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~