保持快乐,善于表达,敢于创新

awk manual-1

上一篇 / 下一篇  2008-06-23 13:51:12 / 个人分类:Shell编程

awk手册

 http://linuxfire.com.cn/~lily/awk.html

1.前言

有关本手册:

这是一本awk学习指引,其重点着重于:

l       awk适于解决哪些问题?

l       awk常见的解题模式为何?

为使读者快速掌握awk解题的模式及特性,本手册系由一些较具代表性的范例及其题解所构成;各范例由浅入深,彼此间相互连贯,范例中并对所使用的awk语法及指令辅以必要的说明.有关awk的指令,函数,...等条列式的说明则收录于附录中,以利读者往后撰写程序时查阅.如此编排,可让读者在短时间内顺畅地学会使用awk来解决问题.建议读者循着范例上机实习,以加深学习效果.

 

读者宜先具备下列背景:

[a.] UNIX环境下的简单操作及基本概念.

例如:文件编辑,文件复制管道,输入/输出重定向等概念

[b.] C语言的基本语法及流程控制指令.

(awk指令并不多,且其中之大部分与C语言中之用法一致,本手册中对该类指令之语法及特性不再加以繁冗的说明,读者若欲深究,可自行翻阅相关的C语言书籍)

 

2.awk概述

为什么使用awk

awk是一种程序语言.它具有一般程序语言常见的功能.

awk语言具有某些特点,:使用直译器(Interpreter)不需先行编译;变量无类型之分(Typeless),可使用文字当数组的下标(Associative Array)...等特色.因此,使用awk撰写程序比起使用其它语言更简洁便利且节省时间. awk还具有一些内建功能,使得awk擅于处理具数据行(Record),字段(Field)型态的资料;此外, awk内建有pipe的功能,可将处理中的数据传送给外部的Shell命令加以处理,再将Shell命令处理后的数据传回awk程序,这个特点也使得awk程序很容易使用系统资源.

由于awk具有上述特色,在问题处理的过程中,可轻易使用awk来撰写一些小工具;这些小工具并非用来解决整个大问题,它们只扮演解决个别问题过程的某些角色,可藉由Shell所提供的pipe将数据按需要传送给不同的小工具进行处理,以解决整个大问题.这种解题方式,使得这些小工具可因不同需求而被重复组合及重用(reuse);也可藉此方式来先行测试大程序原型的可行性与正确性,将来若需要较高的执行速度时再用C语言来改写.这是awk最常被应用之处.若能常常如此处理问题,读者可以以更高的角度来思考抽象的问题,而不会被拘泥于细节的部份.

本手册为awk入门的学习指引,其内容将先强调如何撰写awk程序,未列入进一步解题方式的应用实例,这部分将留待UNIX进阶手册中再行讨论.

 

如何取得awk

一般的UNIX操作系统,本身即附有awk.不同的UNIX操作系统

所附的awk其版本亦不尽相同.若读者所使用的系统上未附有awk,

可透过anonymous ftp到下列地方取得:

phi.sinica.edu.tw:/pub/gnu

ftp.edu.tw:/UNIX/gnu

prep.ai.mit.edu:/pub/gnu

 

awk如何工作

为便于解释awk程序架构,及有关术语(terminology),先以一个员工薪资档(emp.dat ),来加以介绍.

A125 Jenny 100 210

A341 Dan 110 215

P158 Max 130 209

P148 John 125 220

A123 Linda 95 210

文件中各字段依次为员工ID,姓名,薪资率,实际工时. ID中的第一码为部门识别码. "A","P"分别表示"组装""包装"部门.

本小节着重于说明awk程序的主要架构及工作原理,并对一些重要的名词辅以必要的解释.由这部分内容,读者可体会出awk语言的主要精神及awk与其它语程序言的差异处.为便于说明,以条列方式说明于后.

名词定义

l       数据行: awk从数据文件上读取数据的基本单位.以上列文件emp.dat为例, awk读入的

第一笔数据行是"A125 Jenny 100 210"

第二笔数据行是"A341 Dan 110 215"

一般而言,一个数据行就相当于数据文件上的一行资料. (参考:附录B内建变量"RS" )

l       字段(Field) :为数据行上被分隔开的子字符串.

以数据行"A125 Jenny 100 210"为例,

第一栏第二栏第三栏第四栏"A125" "Jenny" 100 210

一般是以空格符来分隔相邻的字段. (参考:附录D内建变量"FS" )

 

3.如何执行awk

UNIX的命令行上键入诸如下列格式的指令: ( "$"Shell命令行上的提示符号)

$awk 'awk程序'数据文件文件名

awk会先编译该程序,然后执行该程序来处理所指定的数据文件.

(上列方式系直接把程序写在UNIX的命令行上)

awk程序的主要结构:

awk程序中主要语法是Pattern { Actions},故常见之awk程序其型态如下:

Pattern1 { Actions1 }

Pattern2 { Actions2 }

......

Pattern3 { Actions3 }

 

Pattern是什么?

awk可接受许多不同型态的Pattern.一般常使用"关系表达式"(Relational expression)来当成Pattern.

例如:

x > 34是一个Pattern,判断变量x34是否存在大于的关系.

x == y是一个Pattern,判断变量x与变量y是否存在等于的关系.

上式中x >34 , x == y便是典型的Pattern.

awk提供C语言中常见的关系运算符(Relational Operators)

>, <, >=, <=, ==, !=

此外, awk还提供~ (match)!~(not match)二个关系运算符(注一).

其用法与涵义如下:

A为一字符串, B为一正则表达式(Regular Expression)

A ~ B判断字符串A中是否包含能匹配(match)B表达式的子字符串.

A !~ B判断字符串A中是否不包含能匹配(match)B表达式的子字符串.

例如:

"banana" ~ /an/整个是一个Pattern.

因为"banana"中含有可以匹配/an/的子字符串,故此关系式成立(true),整个Pattern的值也是true.

相关细节请参考附录A Patterns,附录E Regular Expression

(注一:)有少数awk论著,~, !~当成另一类的Operator,并不视为一种Relational Operator.本手册中将这两个运算符当成一种Relational Operator.

 

Actions是什么?

Actions是由许多awk指令构成.awk的指令与C语言中的指令十分类似.

例如:

awkI/O指令: print, printf( ), getline...

awk流程控制指令: if(...){..} else{..}, while(...){...}...

(请参考附录B --- "Actions" )

 

awk如何处理Pattern { Actions } ?

awk会先判断(Evaluate)Pattern的值,Pattern判断后的值为true (或不为0的数字,或不是空的字符串),awk将执行该Pattern所对应的Actions.反之,Pattern之值不为true,awk将不执行该Pattern所对应的Actions.

 

例如:awk程序中有下列两指令

50 > 23 {print "Hello! The word!!" }

"banana" ~ /123/ { print "Good morning !" }

awk会先判断50 >23是否成立.因为该式成立,所以awk将印出"Hello! The word!!".而另一Pattern"banana" ~/123/,因为"banana"内未含有任何子字符串可match /123/,Pattern之值为false,awk将不会印出"Good morning !"

 

awk如何处理{ Actions }的语法?(缺少Pattern部分)

有时语法Pattern { Actions }, Pattern部分被省略,只剩{Actions}.这种情形表示"无条件执行这个Actions".

 

awk的字段变量

awk所内建的字段变量及其涵意如下:

字段变量

含义

$0

一字符串,其内容为目前awk所读入的数据行.

$1

$0上第一个字段的数据.

$2

$0上第二个字段的数据.

...

其余类推

 

读入数据行时, awk如何更新(update)这些内建的字段变量?

awk从数据文件中读取一个数据行时, awk会使用内建变量$0予以记录.每当$0被改动时(例如:读入新的数据行自行变更$0,...) awk会立刻重新分析$0的字段情况,并将$0上各字段的数据用$1, $2, ..予以记录.

 

awk的内建变量(Built-in Variables)

awk提供了许多内建变量,使用者于程序中可使用这些变量来取得相关信息.常见的内建变量有:

内建变量

含义

NF (Number of Fields)

为一整数,其值表$0上所存在的字段数目.

NR (Number of Records)

为一整数,其值表awk已读入的数据行数目.

FILENAMEawk

正在处理的数据文件文件名.

 

例如: awk从资料文件emp.dat中读入第一笔数据行

"A125 Jenny 100 210"之后,程序中:

$0之值将是"A125 Jenny 100 210"

$1之值为"A125"

$2之值为"Jenny"

$3之值为100

$4之值为210

$NF之值为4

$NR之值为1

$FILENAME之值为"emp.dat"

 

awk的工作流程:

执行awk,它会反复进行下列四步骤.

 

  1. 自动从指定的数据文件中读取一个数据行.
  2. 自动更新(Update)相关的内建变量之值.: NF, NR, $0...
  3. 依次执行程序中所有Pattern { Actions }指令.
  4. 当执行完程序中所有Pattern { Actions },若数据文件中还有未读取的数据,则反复执行步骤1到步骤4.

awk会自动重复进行上述4个步骤,使用者不须于程序中编写这个循环(Loop).

 

打印文件中指定的字段数据并加以计算

awk处理数据时,它会自动从数据文件中一次读取一笔记录,并会

将该数据切分成一个个的字段;程序中可使用$1, $2,...直接取得

各个字段的内容.这个特色让使用者易于用awk编写reformatter来改变量据格式.

[范例:]以文件emp.dat为例,计算每人应发工资并打印报表.

[分析:] awk会自行一次读入一列数据,故程序中仅需告诉

awk如何处理所读入的数据行.

执行如下命令: ( $UNIX命令行上的提示符)

 

$ awk '{ print $2, $3 * $4 }' emp.dat

执行结果如下:

屏幕出现:

Jenny 21000

Dan 23650

Max 27170

John 27500

Linda 19950

 

[说明:]

UNIX命令行上,执行awk的语法为:

$awk 'awk程序'欲处理的资料文件文件名

本范例中的程序部分{print $2, $3 * $4}.

把程序置于命令行时,程序之前后须以'括住.

emp.dat为指定给该程序处理的数据文件文件名.

 

本程序中使用: Pattern { Actions }语法.

Pattern部分被省略,表无任何限制条件.awk读入每笔数据行后都将无条件执行这个Actions.

printawk所提供的输出指令,会将数据输出到stdout(屏幕).

print的参数间彼此以"," (逗号)隔开,印出数据时彼此间会以空白隔开. (参考附录D内建变量OFS)

将上述的程序部分储存于文件pay1.awk.执行命令时再指定awk程序文件之文件名.这是执行awk的另一种方式,特别适用于程序较大的情况,其语法如下:

$ awk -f awk程序文件名数据文件文件名

故执行下列两命令,将产生同样的结果.

$ awk -f pay1.awk emp.dat

$ awk '{ print $2, $3 * $4 }' emp.dat

 

读者可使用"-f"参数,awk主程序使用其它仅含awk函数的文件中的函数

其语法如下:

$ awk -f awk主程序文件名-f awk函数文件名数据文件文件名

(有关awk中函数的声明与使用于7.4中说明)

awk中也提供与C语言中类似用法的printf()函数.使用该函数可进一步控制数据的输出格式.

编辑另一个awk程序如下,并取名为pay2.awk

 

{ printf("%6s Work hours: %3d Pay: %5d\n", $2,$3, $3* $4) }

执行下列命令

 

$awk -f pay2.awk emp.dat

 

执行结果屏幕出现:

 Jenny Work hours: 100 Pay: 21000

   Dan Work hours: 110 Pay: 23650

   Max Work hours: 130 Pay: 27170

  John Work hours: 125 Pay: 27500

 Linda Work hours:  95 Pay: 19950

 

4.选择符合指定条件的记录

Pattern { Action }awk中最主要的语法.若某Pattern之值为真则执行它后方的Action. awk中常使用"关系表达式" (Relational Expression)来当成Pattern.

awk中除了>, <, ==, != ,...等关系运算符( Relational Operators ),另外提供~(match),!~(Not Match)二个关系运算符.利用这两个运算符,可判断某字符串是否包含能匹配所指定正则表达式的子字符串.由于这些特性,很容易使用awk来编写需要字符串比对,判断的程序.

[范例:]承上例,

组装部门员工调薪5%,(组装部门员工之ID"A"开头)

所有员工最后之薪资率若仍低于100,则以100.

编写awk程序打印新的员工薪资率报表.

[分析] :这个程序须先判断所读入的数据行是否合于指定条件,再进行某些动作.awkPattern { Actions }的语法已涵盖这种" if (条件) {动作} "的架构.编写如下之程序,并取名adjust1.awk

$1 ~ /^A.*/ { $3 *= 1.05 } $3<100 { $3 = 100 }

{ printf("%s %8s %d\n", $1, $2, $3)}

执行下列命令:

$awk -f adjust1.awk emp.dat

结果如下:屏幕出现:

A125    Jenny 105

A341      Dan 115

P158      Max 130

P148     John 125

A123    Linda 100

:

awk的工作程序是:从数据文件中每次读入一个数据行,依序执行完程序中所有的Pattern{ Action }指令:

$1~/^A.*/ { $3 *= 1.05 }

$3 < 100 { $3 = 100 }

{printf("%s %8s %d\n",$1,$2,$3)}

再从数据文件中读进下一笔记录继续进行处理.

第一个Pattern { Action }: $1 ~ /^A.*/ { $3 *= 1.05 }

$1 ~ /^A.*/是一个Pattern,用来判断该笔数据行的第一栏是否包含以"A"开头的子字符串.其中/^A.*/是一个Regular Expression,用以表示任何以"A"开头的字符串. (有关Regular Expression之用法参考附录E ).

Actions部分为$3 *= 1.05

$3 *= 1.05$3 = $3 * 1.05意义相同.运算子"*="之用法则与C语言中一样.此后与C语言中用法相同的运算子或语法将不予赘述.

 

第二个Pattern { Actions }: $3 <100 {$3 = 100 }若第三栏的数据内容(表薪资率)小于100,则调整为100.

第三个Pattern { Actions }: {printf("%s %8s %d\n",$1, $2, $3 )}省略了Pattern(无条件执行Actions),故所有数据行调整后的数据都将被印出.

 



TAG:

 

评分:0

我来说两句

Open Toolbar