Never save something for a special occasion. Every day in your life is a special occasion.
分类:
2010-11-13 20:14:14
原文:
gawk 手册 (2005-03-30) GAWK
第一章 前言
第二章 简介
第三章 读取输入档案
第四章 印出
第五章 Patterns
第六章 算式(Expression)作为Actions的
第七章 Actions里面的控制
第八章 内建函式(Built-in Functions)
第九章 使用者定义的函式
第十章 例
第十一章 结论
================SIMPLIFY=======================
第一章 前言
awk 是一个程式语言,对於资料的处理具有很强的功能。对於文字档里的资料做修改、比对、抽取等的处理,awk 能够以很短的程式轻易地完成。gawk 是GNU所做的 awk,包含 awk 的所有功能。
下面2个档案将被用于后面的说明。
档案'BBS-list':
aardvark 555-5553 1200/300 B
alpo-net 555-3412 2400/1200/300 A
barfly 555-7685 1200/300 A
bites 555-1675 2400/1200/300 A
camelot 555-0542 300 C
core 555-2912 1200/300 C
fooey 555-1234 2400/1200/300 B
foot 555-6699 1200/300 B
macfoo 555-6480 1200/300 A
sdace 555-3430 2400/1200/300 A
sabafoo 555-2127 1200/300 C
档案'shipped':
Jan 13 25 15 115
Feb 15 32 24 226
Mar 15 24 34 228
Apr 31 52 63 420
May 16 34 29 208
Jun 31 42 75 492
Jul 24 34 67 436
Aug 15 34 47 316
Sep 13 55 37 277
Oct 29 54 68 525
Nov 20 87 82 577
Dec 17 35 61 401
Jan 21 36 64 620
Feb 26 58 80 652
Mar 24 75 70 495
Apr 21 70 74 514
=======================================
第二章 简介
gawk 的主要功能是针对档案的每一行(line)搜寻指定的 patterns。当一行里有符合指定的 patterns,gawk 就会在此一行执行被指定的 actions。
gawk 程式是由很多的 pattern 与 action 所组成,action 写在大括号 { } 里面,一个pattern後面就跟著一个action。整个 gawk 程式会像下面的样子:
pattern {action}
pattern {action}
在 gawk 程式里面的规则,pattern 或 action 能够被省略,但是两个不能同时被省略。省略的 pattern、action 分别表示 matchAll、print。
2.1 如何执行gawk程式
2个方法执行gawk程式
□如果 gawk 程式很短,则 gawk 可以直接写在 command line,如下所示:
gawk 'program' input-file1 input-file2 ...
其中 program 包括一些 pattern 和 action。
□如果 gawk 程式较长,较为方便的做法是将 gawk 程式存在一个档案,即 patterns 与 actions 写在档名为 program-file(可以有多个) 的档案里面,执行gawk 的格式如下所示:
gawk -f program-file input-file1 input-file2 ...
gawk -f program-file1 -f program-file2 ... input-file1
input-file2 ...
2.2 一个简单的例子
gawk 程式很短,直接写在 command line。
gawk '/foo/ {print $0}' BBS-list
搜寻输入档里的每一行是否含有子字串 'foo',如果含有 'foo' 则执行 action。
action 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。
结果:
fooey 555-1234 2400/1200/300 B
foot 555-6699 1200/300 B
macfoo 555-6480 1200/300 A
sabafoo 555-2127 1200/300 C
/*
测试准备
建立文件夹 gawkTest,将文件 BBS-list、shipped 放在这里;
启动dos,进入 gawkTest;
此时输入 gawk 是不被dos识别的,需要将gawk所在的目录添加到环境变量。
假设gawk的路径为 F:\Editer\gawk-3.1.6-1-bin\bin
1、查看环境变量:path
PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Co
mmon Files\Thunder Network\KanKan\Codecs
2、添加环境变量:set path=%path%;F:\Editer\gawk-3.1.6-1-bin\bin
3、再查看环境变量。
你可能会对下面的文章感兴趣:
《在右键菜单中添加 ms-dos》http://blog.chinaunix.net/u3/116013/showart_2317911.html
*/
/*
注意:
执行下面的命令将报告错误:gawk: ^ invalid char ''' in expression
gawk '/foo/ {print $0}' BBS-list
将单引号改为双引号就没问题了。什么呢?
因为我使用的是Windows,而原文以Unix为测试环境 —— gawk 有针对不同系统的版本。我使用的是 Gawk for windows gawk-3.1.6-1
为保持此简化版和原文一致,后面继续沿用单引号,不再说明。
虽然不喜欢台区的“繁體”和 “别扭的术语”,但不得不面对这样一个现实:经常读到台区的"档案"。所以没有将“别扭的术语”一一替换为“顺眼的术语”。
*/
2.3 一个较复杂的例子
gawk '$1 == "Feb" {sum=$2+$3} END {print sum}' shipped
扫描文档 'shipped' 的每一行,若第1栏等于 "Feb" 则将第2栏、第3栏的值加到变数 sum。
到文档最后时,输出 sum 的值。结果:
84
/*
前面讲了,在我的xp上dos报告 单引号是非法字符,于是用双引号。但如果这里双引号中再用双引号使
执行结果意外:
C:\gawkTest>gawk "$1=="Feb" {sum=$2+$3} END {print sum}" shipped
0
(由JS想到)双引号中单引号,也不行。试试转义字符,OK。
C:\gawkTest>gawk "$1==\"Feb\" {sum=$2+$3} END {print sum}" shipped
84
注意:
1、END 应该大写,否则什么也看不到。
2、不能省略 END {print sum},前面讲的省略是对整个 'program' 而言的,即没有指定action。
*/
=======================================
第三章 读取输入档案
gawk的输入可以从标准输入或指定的档案里读取。输入的读取单位被称为”记录”(records),gawk 在做处理时,是一个记录一个记录地处理。每个记录的内定值是一行(line),一个记录又被分为多个
栏位(fields)。
3.1 如何将输入分解成记录(records)
gawk 语言会把输入分解成记录(record)。记录与记录之间是以record separator 隔开,record separator 的内定值是表示新一行的字元(newline character),因此内定的 record separator 使得文字的每一行是一个记录。
内建变数 RS 用于指定record separator。RS 用串表示,但只有RS的第一个字元是有效的,其它被忽略。例如"\n_"与"\n"等效。RS的内定值是"\n"。
内建变数 FNR 存储当前输入档案已读取的记录个数。
内建变数 NR 储存目前为止所有的输入档案已经被读取的记录个数。
3.2 栏位(field)
gawk 会自动将每个记录分解成多个栏位 (field)。默认栏位分隔符为 whitespace。
在gawk 里,whitespace 的意思是 一个或多个空白 或 tabs。
在 gawk 程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位,依此类推。
例如 若记录如下
This seems like a pretty nice example.
则 $1 是'This',$2 是 'seems',依此类推。
有个地方值得特别注意,第七个栏位或 $7 是'example.'而非'example'。
$NF 表示一个记录的最後一个栏位。上例中,$NF 即 $7,也就是'example.'。
内建变数 NF 表示目前这个记录之栏位的个数。
特别地 $0 表示整个记录。
位栏还可以用于指定 parents 的作用范围,例如:
gawk '$1~/foo/ {print $0}' BBS-list
扫描输入档'BBS-list',若记录的第一个栏位含有子串'foo',则打印此记录。
结果:
fooey 555-1234 2400/1200/300 B
foot 555-6699 1200/300 B
macfoo 555-6480 1200/300 A
sabafoo 555-2127 1200/300 C
3.3 如何将记录分解成栏位
gawk 根据 field separator 将一个记录分解成栏位。
内建变数 FS 表示 field separator ,默认为 whitespace。
例如 若 field separator 是'oo',则下面的行:
moo goo gai pan
会被分成三个栏位:'m'、' g'、' gai pan'。
可以使用'='来改变 FS 的值。例如:
gawk 'BEGIN {FS=","}; {print $2}'
输入:
John Q. Smith, 29 Oak St., Walamazoo, MI 42139
结果:
打印 ' 29 Oak St.'。
BEGIN 後面的 action 会在第一个记录被读取前执行。
=======================================
第四章 印出
最常见的 actions 是 印出(printing)。
简单的印出,使用 printe。复杂格式的印出,使用 printf 。
4.1 print
print 用在简单、标准的输出格式。格式如下:
print item1, item2, ...
输出时,各个 item 之间以一个空白分开,最後会换行(newline)。
不带参数的 print 与'print $0'等效,即印出当前记录(record)。
要印出空白行可使用'print ""'。串字面量用双引号括起来,例如
'print "Hello there"'。
示例:
把每个输入记录的前二个栏位印出。
gawk '{print $1,$2}' shipped
结果:
Jan 13
Feb 15
...
Dec 17
Jan 21
...
Apr 21
4.2 Output Separators
前面提过如果要 print 多个 item,item 之间用逗点分开,印出时各个item会被一个空白隔开。
内建变数 OFS 指定 output field separator。OFS 的初始值为" ",即一格的空白。
你可以指定任何串为 output field separator。
整个 print 的输出被称为 output record。output record 之後输出的串称为 output record separator。
内建变数 ORS 用来指明 output record separator。ORS 的初始值为 "\n",也就是换行。
下面这个例子会印出每个记录的第一个栏位和第二个栏位,栏位之间以分号';'分开,每行输出之後会加入一个空白行。
gawk 'BEGIN {OFS=";"; ORS="\n\n"} {print $1, $2}' BBS-list
结果:
aardvark;555-5553
alpo-net;555-3412
...
sdace;555-3430
sabafoo;555-2127
4.3 printf
printf 提供丰富的输出格式。printf 可以指定每个 item 印出的宽度,也可以指定数字的各种型式。
格式:
printf format, item1, item2, ...
format 的型式与 ANSI C 的 printf 之格式相同。
printf 并不会做自动换行的动作。内建变数 OFS 与 ORS 对 printf 没有任何影响。
格式的指定以字元'%'开始,後面接著格式控制字母。格式控制字母如下所示:
'c' 将数字以 ASCII 字元印出。例如'printf "%C",65'会印出字元'A'。
'd' 印出十进位的整数。
'i' 印出十进位的整数。
'e' 将数字以科学符号的形式印出。例如
print "$4.3e",1950
结果会印出'1.950e+03'。
'f' 将数字以浮点的形式印出。
'g' 将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印出。
'o' 印出无号的八进位整数。
's' 印出一个字串。
'x' 印出无号的十六进位整数。10至15以'a'至'f'表示。
'X' 印出无号的十六进位整数。10至15以'A'至'F"表示。
'%' 它并不是真正的格式控制字母,'%%"将印出"%'。
在 % 与格式控制字母之间可加入 modifier,modifier 是用来进一步控制输出的格式。
可能的 modifier 如下所示:
'-' 使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在被指定的宽度向右靠齐。
例如:
printf "%-4S", "foo"
会印出'foo '。
'width' 这一个数字指示相对应的栏位印出时的最小宽度。例如:
printf "%4s","foo"
会印出' foo'。
'.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。
如果是要印出一个字串,它指定此字串最多会被印出多少个字元。
=======================================
第五章 patterns
只有匹配 pattern 的输入记录(record),才会执行相应的 action。
5.1 Pattern的种类
/regular expression/
正则表达式。
expression
一个单一的 expression。当一个值不为 0 或一个字串不是空的,则可视为符合。 //???
pat1,pat2
一对的 patterns 以逗号分开,指定记录的□围。
BEGIN
END
特别的 pattern, gawk 在开始执行或要结束时会分别执行相应的 action。
null
空的pattern,对於每个输入记录皆视为符合pattern。
5.2 Regular Expressions当作Patterns
regular expression 简写 regexp,是一种描述字串的方法。一个 regular expression 以斜线('/')包围当作 gawk 的 pattern。
如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,对於任何输入记录含有'foo'则视为符合。
下面的例子会将含有'foo'的输入记录之第2个栏位印出。
gawk '/foo/ {print $2}' BBS-list
结果:
555-1234
555-6699
555-6480
555-2127
regexp 也能使用在比较的算式。
exp ~ /regexp/
如果 exp 符合 regexp,则结果为真(true)。
exp !~ /regexp/
如果 exp 不符合 regexp,则结果为真。
5.3 比较的算式当作Patterns
比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於、小於。
下面列出一些比较的pattern:
x
x>y 如果 x 大於 y,则结果为真。
x>=y 如果 x 大於、等於 y,则结果为真。
x==y 如果 x 等於 y,则结果为真。
x!=y 如果 x 不等於 y,则结果为真。
x~y 如果 x 符合 regular expression y,则结果为真。
x!~y 如果 x 不符合 regular expression y,则结果为真。
上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较;否则它们会被转换成字串且以字串的形式做比较。
两个字串的比较,会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同的地方出现为止。
如果两个字串在较短的一个结束之前是相等,则视为长的字串比短的字串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。
5.4 使用布林运算的Patterns
一个布林(boolean) pattern 是使用布林运算"或"('||'),"及"('&&'),"反"('!')来组合其它的pattern。
例如:
gawk '/2400/ && /foo/' BBS-list
gawk '/2400/ || /foo/' BBS-list
gawk '! /foo/' BBS-list
=======================================
第六章 算式(Expression)作为Actions的
算式(Expression) 是gawk程式里面action的基本构成者。
6.1 算术运算
gawk 里的算术运算如下所示:
x+y 加
x-y 减
-x 负
+x 正。实际上没有任何影响。
x*y 乘
x/y 除
x%y 求馀数。例如 5%3=2。
x^y
x**y x 的 y 次方。例如2^3=8。
6.2 比较算式与布林算式
比较算式 (comparison expression) 用来比较字串或数字的关系。运算符号与 C 语言相同。表列如下:
x
x>y
x>=y
x==y
x!=y
x~y
x!~y
比较的结果为真(true)则其值是 1,否则其值是 0。
布林算式(boolean expression)有下面三种:
boolean1 && boolean2
boolean1 || boolean2
! boolean
6.3 条件算式(Conditional Expressions)
一个条件式算式是一种特别的算式,它含有3个运算元。条件式算式与C语言的相同:
selector ? if-true-exp : if-false-exp
它有3个子算式。第一个子算式selector 首先会被计算。如果是真,则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-exp 会被计算且它的值变成整个算式的值。
例如下面的例子会产生x的绝对值:
x>0 ? x : -x
=======================================
第七章 Actions里面的控制
在 gawk 程式里面,控制诸如 if、while 等控制程式执行的流程。在 gawk 里的控制与 C 的类似。
很多的控制会包括其它的,被包括的称为 body。假如 body 里面包括一个以上的,必须以大括弧 { } 将这些括起来,而各个之间需以换行(newline)或分号隔开。
7.1 if
if (condition) then-body [else else-body]
如果 condition 为真(true),则执行 then-body,否则执行 else-body。
例如:
if (x % 2 == 0)
print "x is even"
else
print "x is odd"
7.2 while
while (condition)
body
印出每个输入记录(record)的前三个栏位。
gawk '{ i=1
while (i <= 3) {
print $i
i++
}
}'
7.3 do-while
do
body
while (condition)
印出每个输入记录十次。
gawk '{ i= 1
do {
print $0
i++
} while (i <= 10)
}'
7.4 for
for (initialization; condition; increment)
body
印出每个输入记录的前三个栏位。
gawk '{ for (i=1; i<=3; i++)
print $i
}'
7.5 break
break 会跳出包含它的 for、while、do-while 回圈的最内层。
下面的例子会找出任何整数的最小除数,它也会判断是否为质数。
gawk '# find smallest divisor of num
{ num=$1
for (div=2; div*div <=num; div++)
if (num % div == 0)
break
if (num % div == 0)
printf "Smallest divisor of %d is %d\n", num, div
else
printf "%d is prime\n", num }'
7.6 continue
continue 使用於 for、while、do-while 回圈内部,它会跳过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。
下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。
gawk 'BEGIN {
for (x=0; x<=20; x++) {
if (x==5)
continue
printf ("%d",x)
}
print ""
}'
7.7 next 、next file 、exit
next 强迫 gawk 立刻停止处理目前的记录(record)而继续下一个记录。
next file 类似 next。然而,它强迫 gawk 立刻停止处理目前的资料档。
exit 会使得 gawk 程式停止执行而跳出。然而,如果 END 出现,它会去执行 END 的 actions。// ?
=======================================
第八章 内建函式(Built-in Functions)
内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建函式。
8.1 数值方面的内建函式
int(x) 求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9)是 3,int(-3.9) 是 -3。
sqrt(x) 求出 x 正的平方根值。例 sqrt(4)=2
exp(x) 求出 e 的 x 次方。例 exp(2) 即是求 e*e 。
log(x) 求出 x 的自然对数。
sin(x) 求出 x 的 sine 值,x 是弪度量。
cos(x) 求出 x 的 cosine 值,x 是弪度量。
atan2(y,x) 求 y/x 的 arctangent 值,所求出的值其单位是弪度量。
rand() 得出一个乱数值。它平均分布在 0 和 1 之间,但不会是 0 或 1。
对于相同的 seed,rand 产生相同的序列。
srand(x) 设定 seed 为 x。若省略引数 x,即 srand(),则以现在的日期、时间为 seed。
srand 的传回值(return value)是前次所设定的 seed 值。
8.2 字串方面的内建函式
index(in, find)
在串 in 中寻找子串 find 第一次出现的地方,传回位置(base 1)。若未找到则传回值 0。
例如:
print index("peanut","an")
3。
length(string)
求出 string 有几个字元。
例如:
length("abcde")
5。
match(string,regexp)
match 函式会在字串 string 里面,寻找符合 regexp 的最长、最靠左边的子字串。传回值是 regexp 在 string 的开始位置,即 index 值。
match 函式会设定内在变数 RSTART 等於 index,它也会设定内在变数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为
0、RLENGTH 为 -1。
sprintf(format,expression1,...)
举 printf 类似,但是 sprintf 并不印出,而是传回字串。
例如:
sprintf("pi = %.2f (approx.)',22/7)
传回的字串为"pi = 3.14 (approx.)"
sub(regexp, replacement,target)
在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,以字串 replacement 代替最左边的 regexp。
例如:
str = "water, water, everywhere"
sub(/at/, "ith",str)
结果字串str会变成
"wither, water, everywhere"
gsub(regexp, replacement, target)
gsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的所有地方,以字串 replacement 代替所有的 regexp。
例如:
str="water, water, everywhere"
gsub(/at/, "ith",str)
结果字串str会变成
'wither, wither, everywhere"
substr(string, start, length)
传回字串 string 的子字串,这个子字串的长度为 length 个字元,从第 start 个位置开始。
例如:
substr("washington",5,3)
传回值为"ing"
若省略 length 则至结束。
例如:
substr("washington",5)
传回值为"ington"
tolower(string)
将字串string的大写字母改为小写字母。
例如:
tolower("MiXeD cAsE 123")
传回值为"mixed case 123"
toupper(string)
将字串string的小写字母改为大写字母。
8.3 输入输出的内建函式
close(filename)
将输入或输出的档案 filename 关闭。
system(command)
此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk 程式。
例如:
BEGIN {system("ls")}
=======================================
第九章 使用者定义的函式(User-defined Functions)
允许用户自定义函式。用法与内建函式的一样。
9.1 函式定义的格式
函式的定义可以放在 gawk 程式的任何地方。
一个使用者定义的函式其格式如下:
function name (parameter-list) {
body-of-function
}
name 是所定义的函式之名称。一个正确的函式名称可包括一序列的字母、数字、下标线 (underscores),但是不可用数字做开头。
parameter-list 是列出函式的全部引数(argument),各个引数之间以逗点隔开。
body-of-function 包含 gawk 的 (statement)。它是函式定义里最重要的部份,它决定函式实际要做何种事。 //?
9.2 函式定义的例子
将每个记录的第一个栏位之值的平方与第二个栏位之值的平方加起来。
{print "sum =",SquareSum($1,$2)}
function SquareSum(x,y) {
sum=x*x+y*y
return sum
}
=======================================
第十章 gawk 程式的一些例子。
gawk '{if (NF > max) max = NF}
END {print max}'
此程式会印出所有输入行之中,栏位的最大个数。
gawk 'length($0) > 80'
此程式会印出一行超过 80 个字元的每一行。
此处只有 pattern 被列出,action 是采用内定的 print。
gawk 'NF > 0'
对於拥有至少一个栏位的所有行,此程式皆会印出。
这是一个简单的方法,将一个档案里的所有空白行删除。
gawk '{if (NF > 0) print}'
同上。
gawk 'BEGIN {for (i = 1; i <= 7; i++)
print int(101 * rand())}'
此程式会印出□围是 0 到 100 之间的 7 个乱数值。
ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
此程式会印出所有指定的档案之bytes数目的总和。
expand file | gawk '{if (x < length()) x = length()}
END {print "maximum line-length is " x}'
此程式会将指定档案里最长一行的长度印出。
expand 会将 tab 改成 space,所以是用实际的右边界来做长度的比较。
gawk 'BEGIN {FS = ":"}
{print $1 | "sort"}' /etc/passwd
此程式会将所有使用者的login名称,依照字母的顺序印出。// sort ?
gawk '{nlines++}
END {print nlines}'
此程式会将一个档案的总行数印出。
gawk 'END {print NR}'
此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk来做。
gawk '{print NR,$0}'
此程式印出档案的内容时,会在每行的最前面印出行号,它的功能与 'cat -n' 类似。
=======================================
第十一章 结论
gawk 对於资料的处理具有很强的功能。它能够以很短的程式完成想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件工作,以 gawk 程式来写会比用其它程式语言来写短很多。
gawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使用。
=======================================