现在的位置: 首页 > 综合 > 正文

awk

2013年10月16日 ⁄ 综合 ⁄ 共 6347字 ⁄ 字号 评论关闭
 

awk 手册

 

1. 前言

有关本手册 :

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

l       
awk 适于解决哪些问题 ?

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

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

 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如何工作

为便于解释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, 判断变量 x 34 是否存在大于的关系.

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 语言中的指令十分类似.

例如 :

awk I/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 处理数据时, 它会自动从数据文件中一次读取一笔记录(Record), 并会将该数据切分成一个个的字段(Field); 程序中可使用
$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程序打印新的员工薪资率报表.

[分析 ] : 这个程序须先判断所读入的数据行是否合于指定条件, 再进行某些动作.awk Pattern
{ 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), 故所有数据行调整后的数据都将被印出.

 

5. awk 中数组

awk程序中允许使用字符串当做数组的下标(index). 利用这个特色十分有助于资料统计工作.(使用字符串当下标的数组称为Associative Array)

首先建立一个数据文件, 并取名为
reg.dat.
此为一学生注册的资料文件; 第一栏为学生姓名, 其后为该生所修课程.

Mary O.S. Arch. Discrete

Steve D.S. Algorithm Arch.

Wang Discrete Graphics O.S.

Lisa Graphics A.I.

Lily Discrete Algorithm

awk中数组的特性

使用字符串当数组的下标

抱歉!评论已关闭.