TA的每日心情 | 奋斗 2019-2-12 09:32 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到 累计签到:1 天 连续签到:1 天
|
马上加入,结交更多好友,共享更多资料,让你轻松玩转电力研学社区!
您需要 登录 才可以下载或查看,没有账号?立即加入
×
GAWK' N p/ {9 g6 _& ]( j) t
第一章 前言
$ {$ e6 C/ y/ z0 r2 A) b第二章 简介. L+ p: }+ I' Q4 k6 y! H* \
第三章 读取输入档案6 v4 J8 E5 F2 E5 z) x( K6 o/ Q! x
第四章 印出9 {9 t/ n& \* A3 {" p: H; Q
第五章 Patterns
: M6 ^( z0 {4 k第六章 算式(Expression)作为Actions的叙述7 C$ D! ]* ~- A g1 {1 H
第七章 Actions里面的控制叙述
- l3 `" b* e, c' T第八章 内建函式(Built-in Functions)8 V( u% x1 g/ g+ w* @; R7 ?. j
第九章 使用者定义的函式
( j3 ?7 d( P3 Q* D& R第十章 □例
- d; F$ ?1 j& [% {1 o第十一章 结论4 x6 s% {. Q6 i# K" \8 x
' u$ U. j4 i7 |! |5 P) V=======================================
) y. Z) d4 ^' k _第一章 前言, o. B6 I1 p0 {. X! s1 L! \2 w
awk 是一个程式语言,对於资料的处理具有很强的功能。对於文& @1 `/ r1 K; j7 o }
字档里的资料做修改、比对、抽取等的处理,awk 能够以很短的程式; z' t& X! p' w) k) J
轻易地完成。如果使用 C 或 Pascal 等语言写程式完成上述的动作,
- W, ^: e: H2 @: }1 w会不方便且很花费时间,所写的程式也会很大。
6 H* x! }* ^, t9 Iawk 能够依照使用者的定义格式来分解输入资料,也可依照使用9 _; o0 P7 L+ t; f6 n9 x
者定义的格式来印出资料。" d# ?, `+ M4 O8 z, Y
awk 名称的由来是由它的原始设计者的姓氏之第一个字母而命名" R) K& a1 }3 u1 H- I& g
:Alfred V. Aho, Peter J. Weinberger, Brian W. Kernighan。
7 A3 P+ D1 A2 A; A2 X& E! C3 `awk最初在1977年完成。一个新版本的awk在1985年被发表,它的功能
: [) v2 s( T) d* l' ~比旧版本增强不少。7 K: \3 ?; j; L0 M/ k8 z V! |
gawk 是GNU所做的 awk,gawk 最初在1986年完成,之後不断地, S$ ?" X1 v0 }9 p9 P1 j
被改进、更新。gawk 包含 awk 的所有功能。
$ S, h9 s# {' I0 e% M* p6 {3 N# ~往後的 gawk 将以下面的2个输入档案来做例子说明。
2 K/ k2 U8 V# Z: |2 ]- C档案'BBS-list':
9 ]2 @: R1 }: J& U- |aardvark 555-5553 1200/300 B
3 U! M: E9 p& X5 K- Q# Yalpo-net 555-3412 2400/1200/300 A9 w( }0 C, F w$ `7 W) q% C
barfly 555-7685 1200/300 A
, @( m, I9 t' V7 ^3 H, Zbites 555-1675 2400/1200/300 A n6 K2 g. C8 A+ ?6 U. }- A
camelot 555-0542 300 C/ n W- O( h+ l
core 555-2912 1200/300 C5 K- k2 O6 E$ [. `6 ~; K
fooey 555-1234 2400/1200/300 B
' N8 _) K" I$ f4 Jfoot 555-6699 1200/300 B
* ?- M9 y& C- A# k+ K6 xmacfoo 555-6480 1200/300 A% D# A) | [8 }& }
sdace 555-3430 2400/1200/300 A
* W9 R' O! J A# x, N; Fsabafoo 555-2127 1200/300 C
# `6 u" R; L+ S! W8 F档案'shipped': Q1 ] `) k# M" ~9 C4 m4 F
Jan 13 25 15 1159 y* K# Y3 a+ y3 Y
Feb 15 32 24 226( G6 e' {' K; q4 y& `+ r7 d2 g- o
Mar 15 24 34 228
8 P% _( j) Z3 ]5 Q! ?Apr 31 52 63 420! C% n4 R) m) D4 N0 ^
May 16 34 29 208
7 U u$ a, _3 c( uJun 31 42 75 492% v2 k6 L" q A! m4 i
Jul 24 34 67 436
g" I# J4 Q! pAug 15 34 47 316' e/ t6 X" ] ~% J* @6 l4 L. g$ Y
Sep 13 55 37 277
' i6 i; j; T( g' E% Q/ ?1 k5 |Oct 29 54 68 525
C3 [) J- ~ d9 T! O. h/ WNov 20 87 82 577
1 z7 j+ g/ [0 v6 \Dec 17 35 61 4019 ~; R3 s, A$ s |
Jan 21 36 64 620
( ?% P! k( |" e$ K8 ~1 c" hFeb 26 58 80 652
' Q/ F! x C4 i1 ~2 K, HMar 24 75 70 495( K& Y: Y* M6 u1 i: K
Apr 21 70 74 514
2 i8 _. V: m8 q! m0 V2 g
# X" n$ s7 F- m, t第二章 简介/ L, l: H- c2 G( s! q0 o! ^
gawk 的主要功能是针对档案的每一行(line)搜寻指定的 patterns
- T8 F3 n" M, u q) I。当一行里有符合指定的 patterns,gawk 就会在此一行执行被指定8 a" Y9 [& N! W1 j" L
的 actions。 gawk 依此方式处理输入档案的每一行直到输入档案结
E' @* w$ b! e束。
/ ^/ R( ~! u8 e2 `% Y; Xgawk 程式是由很多的 pattern 与 action 所组成,action 写在
! L8 Y3 E. w& K1 N大括号 { } 里面,一个pattern後面就跟著一个action。整个 gawk 程
: t) ~) n: h) j, A" u式会像下面的样子:
0 I5 Y/ |, [, t+ \pattern {action}
# B% r" X/ o. O7 F* {8 \; ~5 mpattern {action}
% ^# M& l' q3 ]# C; I在 gawk 程式里面的规则,pattern 或 action 能够被省略,但2 h4 w, \2 h/ |$ D# u
是两个不能同时被省略。如果 pattern 被省略,对於输入档里面的5 z7 F1 m0 v. v) b% L3 I$ d& b
每一行,action 都会被执行。如果 action 被省略,内定的 action3 `7 S5 [. p5 q7 j
则会印出所有符合 pattern 的输入行。2 ^) r- O& U! V
8 n8 b9 N" T6 j* }$ k% C2.1 如何执行gawk程式 ?5 g5 g' @+ L( Z% I2 E0 |
基本上,有2个方法可以执行gawk程式。1 h1 U4 A a# Q: M
□如果 gawk 程式很短,则 gawk 可以直接写在 command line,如下所示:
8 D* d% z; s% n4 t5 Rgawk 'program' input-file1 input-file2 ...% D! Y! D. N. `! N$ f# ^% V
其中 program 包括一些 pattern 和 action。
& R7 @" O9 v2 ]. W3 Q2 _2 H□如果 gawk 程式较长,较为方便的做法是将 gawk 程式存在一个档案,
4 A* v! I, _3 n; s即 patterns 与 actions 写在档名为 program-file 的档案里面,执行
5 }4 {" D: x7 }! L1 A- Q' Agawk 的格式如下所示:
9 k; o( s( ~. d2 `: l. |# Y% zgawk -f program-file input-file1 input-file2 ...
/ |+ U& i1 {: T" y$ Zgawk 程式的档案不止一个时,执行gawk 的格式如下所示:
. X6 z9 T- P0 j" g' T0 l+ rgawk -f program-file1 -f program-file2 ... input-file1
2 F1 ]% Q0 I: p! u2 a- Uinput-file2 ... x' e6 E$ O; l
' j# E( j W1 D2 O& g/ |6 t' l) Z
2.2 一个简单的例子5 t7 [" x$ S# B7 `! H3 ^$ I" N
现在我们举一个简单的例子,因为 gawk 程式很短,所以将 gawk 程
5 s: G* { ~: d5 u式直接写在 command line。
% U- e7 }7 B. \; Igawk '/foo/ {print $0}' BBS-list4 t. b8 J: g2 B
实际的 gawk 程式为 /foo/ {print $0}。/foo/ 为 pattern,意思为搜" J' Z) _0 L' R4 f0 \
寻输入档里的每一行是否含有子字串 'foo',如果含有 'foo' 则执行 action。3 [! ^' j U/ V# y; n' c
action 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。4 E9 L% R% M/ T" X6 I# u
执行完上述指令後,会印出下面的结果:9 y6 G+ f; }+ X3 \% D
fooey 555-1234 2400/1200/300 B
& t7 R3 y* N ?7 _6 k5 M/ cfoot 555-6699 1200/300 B
) T* p, Y) h! D9 omacfoo 555-6480 1200/300 A
4 B( w' v6 V6 D7 Vsabafoo 555-2127 1200/300 C V) ?) e S7 D- E
3 [ H2 Q1 Q. t- l+ n2.3 一个较复杂的例子
# i' M3 U j% ygawk '$1 == "Feb" {sum=$2+$3} END {print sum}' shipped2 q3 ]2 S& d2 l8 ^6 {* c! h6 r& w
现在这个例子会将输入档 'shipped' 的第一个栏位与 "Feb" 做比较
# V$ _- u% ?' G) Z* f,如果相等,则其对应的第2栏位与第3栏位的值会被加到变数 sum。' H5 _- s% }3 J0 U
对於输入档的每一行重复上述的动作,直到输入档的每一行都被处理
7 I, e4 }# y' R7 |过为止。最後将 sum 的值印出。END {print sum} 的意思为在所有的输1 L3 g4 U2 K3 N$ ~" V
入读完之後,执行一次 print sum 的动作,也就是把 sum 的值印出。6 `' B% k7 h: {
下面是执行的结果:
; i4 i' i/ M6 a! | q) s84
' y0 v; y" j% j6 u% p p6 I
4 x5 Z3 T4 y. B3 L第三章 读取输入档案) B9 @' Z8 a8 w) L
gawk的输入可以从标准输入或指定的档案里读取。输入的读取单
0 t: Y( |% I% d2 l1 @位被称为”记录”(records),gawk 在做处理时,是一个记录一个记
! L' f0 b# n3 b, X- d录地处理。每个记录的内定值是一行(line),一个记录又被分为多个6 v) [4 p7 Z, p6 h+ ^
栏位(fields)。: o3 B" ?. U$ m" p; V
' G0 k7 i7 E4 m8 b" N6 J* H3.1 如何将输入分解成记录(records)
/ p- d u% a; p3 k4 [gawk 语言会把输入分解成记录(record)。记录与记录之间是以, o+ D4 M' [/ K2 q% S* u5 u
record separator 隔开,record separator 的内定值是表示新一行的
& A3 _& `4 d; W, t字元(newline character),因此内定的 record separator 使得文字
4 i* ^% _+ l6 @6 v5 Y+ _的每一行是一个记录。
) f- }( D* o6 M7 h, grecord separator 随著内建变数 RS 的改变而改变。RS 是一个字串,
( V. i) Q# R# f0 d/ e9 i它的内定值是"\n"。仅有 RS 的第一个字元是有效的,它被当作 record/ S$ ?# q5 R5 A. }# R' Y! w) ]3 P
separator,而 RS 的其它字元会被忽略。5 Y; L# y8 \7 M9 ~+ Q" H
内建变数 FNR 会储存目前的输入档案已经被读取的记录之个数。内- n. r0 j! {9 D2 U" i4 b
建变数 NR 会储存目前为止所有的输入档案已经被读取的记录之个数。
; y$ i) K7 ~6 u* |% s8 X6 H/ P: y) S0 Z# \; L' O
3.2 栏位(field)
: F4 P8 @) c0 D5 S# Cgawk 会自动将每个记录分解成多个栏位 (field)。类似於字在一
$ U7 d! X; U. k1 N. ^0 ~行里面,gawk 的内定动作会认为栏位之间是以 whitespace 分开。在
& W' e$ v- P2 u4 [gawk 里,whitespace 的意思是一个或多个空白或 tabs。! H) d. s( n- X9 e/ e& J
在 gawk 程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位* i( Q% q5 X! e" F& |6 p& @
,依此类推。举个例子,假设输入的一行如下所示:1 T2 W3 i: Q6 ?6 I3 N
This seems like a pretty nice example.) ~" }' B7 M! ^
第一个栏位或 $1 是'This',第二个栏位或 $2 是 'seems',依此类推。8 z/ w5 M T- R4 ~/ ]7 X! ]8 h- p
有个地方值得特别注意,第七个栏位或 $7 是'example.'而非'example'。. A( X4 Q5 y ]) [# k. c: K
不论有多少栏位,$NF 可用来表示一个记录的最後一个栏位。以7 s: I1 B1 q( W8 L
上面的例子为例,$NF 与 $7 相同,也就是'example.'。4 E# P' Y1 f) [6 o0 k4 U
NF 是一个内建变数,它的值表示目前这个记录之栏位的个数。! M6 n* B" D: A" Y9 s2 Y. i# {
$0,看起来好像是第零个栏位,它是一个特例,它表示整个记录。
) F' k" _- O j2 Z下面是一个较复杂的例子:
* ^2 G' b' J0 @, @! Ogawk '$1~/foo/ {print $0}' BBS-list1 |/ |$ j4 {4 D' h9 b! L* k
结果如下:
. m5 Y! k' m e7 k3 x9 cfooey 555-1234 2400/1200/300 B
8 t4 p( |1 O2 W1 R9 k' {foot 555-6699 1200/300 B6 U4 t6 l8 O& K- T O
macfoo 555-6480 1200/300 A9 r. [) }8 k# ^+ M
sabafoo 555-2127 1200/300 C
3 |; Y9 k/ A; V4 i& x6 O这个例子是把输入档'BBS-list'的每个记录的第一个栏位作检查,如; B' q, e8 z$ w) `7 {: Z
果它含有子字串'foo',则这一个记录会被印出。# [( \- v4 z8 O
& T# y% M" q+ Q G$ g! Y C; Z2 g8 P
3.3 如何将记录分解成栏位) v- F- }* S( k' p0 V' T% ~0 _
gawk 根据 field separator 将一个记录分解成栏位。field sepa-
# ]& H0 Z$ r9 Y8 r5 t7 ?9 drator 以内建变数 FS 表示。
2 L" p2 {4 h$ ]$ w/ U3 j2 R* A+ p举个例子,假如 field separator 是'oo',则下面的行:; k0 p2 Z3 H+ z w: l+ ~6 }" F
moo goo gai pan0 |5 J8 W) Y2 B6 O/ O2 ?, L
会被分成三个栏位:'m'、' g'、' gai pan'。
4 L C: I* u3 x/ P在 gawk 程式里,可以使用'='来改变 FS 的值。例如:
0 b0 F- d8 N! ]9 x X4 i4 igawk 'BEGIN {FS=","}; {print $2}'
- w+ N5 x* ~( v1 ]5 k- `/ u- i0 N5 v输入行如下:
7 E9 ~+ V' s" y: mJohn Q. Smith, 29 Oak St., Walamazoo, MI 42139
" y0 w* S9 G( k+ t* [$ v# Q执行gawk的结果将印出字串 ' 29 Oak St.'。BEGIN 後面的 action 会在
$ |9 X* z1 C# l% V% E& \1 A第一个记录被读取之前执行一次。7 r8 Q! _& d3 U$ k8 n- u
% W4 ]/ G% M' j8 v/ _% j
第四章 印出5 v( R0 [0 z+ R! [7 Q/ \/ w9 ~
在gawk程式里,actions 最常做的事就是印出(printing)。简单
. ~4 b2 G/ P5 R- G9 B; |的印出,使用 printe叙述。复杂格式的印出,使用 printf 叙述。) z+ I {) P6 o# w
/ `6 F4 f; U/ U1 ?/ l8 z( [4.1 print叙述% r% f$ U5 D. R& e. R
print 叙述用在简单、标准的输出格式。叙述的格式如下所示:
+ x$ _9 z1 F0 p+ Xprint item1, item2, ...
5 W5 j6 X9 r7 S9 X+ {输出时,各个 item 之间会以一个空白分开,最後会换行(newline)。
, N% e7 a, ]8 U( o9 \如果 'print'叙述之後没有跟著任何东西,它与'print $0'的效+ K6 q' r" z9 u3 p7 B, d5 f
果一样,它会印出现在的记录(record)。要印出空白行可使用'print& Q& p) C+ m8 o1 r8 m- _8 o" G& y
""'。 印出一段固定的文字,可用双引号将文字的两边括起来,例如
, n3 V- ^+ @9 i'print "Hello there"'。' H: V' W) a; J v
这里是一个例子,它会把每个输入记录的前二个栏位印出:+ G9 f% s6 _6 ?% _
gawk '{print $1,$2}' shipped5 r4 i- @8 [ }/ I8 J$ r- t
结果如下所示:
+ `! J7 k+ U" }Jan 13
( M* Q$ U- Z% t& {: V" O2 BFeb 15, ]* z% O! @% H* H# n- f; `0 s; b
Mar 15
7 j- |7 }1 v' U0 TApr 310 u1 H1 S; n0 d4 j; g
May 16: @+ H& e: F- ]% \$ [1 k
Jun 31
6 c& h4 b! K2 |: b; r1 x4 PJul 24
9 s0 D/ n4 p: H' K& v! nAug 15
9 @9 U X& _ w; D& p0 P6 ^; rSep 13
" m9 ~; G: ^7 c2 U( |8 C/ ^% a+ [9 {Oct 29
, C5 M% K7 A k& e% U; S, h" {. TNov 20( _+ j, f1 G! x
Dec 17
% x/ r$ {: I$ y. }: KJan 21
, }( g2 j5 m( c% c9 cFeb 26
2 K/ j6 A8 T$ v1 @: }; IMar 24
4 a2 F9 K/ b1 |Apr 21. [$ ~" p, w) S. S$ b
: w5 n: h# `# [) Y3 B) Z
4.2 Output Separators
) J" a8 [% r8 p, _前面我们已提过如果 print 叙述包含有多个 item,item 之间& n* X5 a- W& \ J' R
用逗点分开,则印出时各个item会被一个空白隔开。你能够使用任何6 f1 D% n! |/ N8 M
的字串作为 output field separator,可以经由内建变数 OFS 的设 {" q3 i% m) U
定来更改 output field separator。OFS 的初始值为" ",即一格的
. C. j" f; g3 ~空白。
8 l: F: K& `) j' t* U6 `6 X- `整个 print 叙述的输出被称为 output record。print 叙述输7 o" _ m: q5 E7 F: A3 B& T! ]& f
出 output record 之後,会接著输出一个字串,此字串称为 output% s! ~+ ^, u7 Z K# B4 u
record separator。内建变数 ORS 用来指明此字串。ORS 的初始值, X; i B3 x, P6 k+ G/ t, s
为 "\n",也就是换行。
; P2 h( _7 w1 V7 ^3 Z3 c下面这个例子会印出每个记录的第一个栏位和第二个栏位,此二/ J: w3 F' y" K B+ `, { Y
个栏位之间以分号';'分开,每行输出之後会加入一个空白行。9 z# Z" w0 R& |% v6 h7 x
gawk 'BEGIN {OFS=";"; ORS="\n\n"} {print $1, $2}' BBS-list! Z$ q2 z! N6 F1 g3 [
结果如下所示: Z" s# p% c. u
aardvark;555-5553
. S4 S' H1 y; q2 ^# z+ Y) balpo-net;555-3412
6 O; D' X# M9 U0 F0 |2 kbarfly;555-76859 u' C$ J0 I( [ O3 Y
bites;555-1675: |7 }/ C- u" F/ Z) d7 K
camelot;555-0542
' z$ \) g X$ k7 Wcore;555-2912
) a& _$ T9 f0 S; o/ L# r- f, efooey;555-1234! d# P$ X+ b, J r6 e5 H
foot;555-6699
. f \5 J& N# E2 Lmacfoo;555-6480; H! r( p4 E o. b) O- X
sdace;555-3430$ O; x ` a2 E/ N! S3 I# ]
sabafoo;555-2127! Q; a1 R$ w# @, o. U( W5 \+ A+ S
. ~% J9 p" ]+ c& }4.3 printf叙述
0 V& u4 L: h% J$ ^printf 叙述会使得输出格式较容易精确地控制。printf 叙述可以4 \) u0 ]7 ?6 w$ x$ \
指定每个 item 印出的宽度,也可以指定数字的各种型式。* ~( r# G5 n0 F
printf 叙述的格式如下:% Q+ H* M: K" e! X
printf format, item1, item2, ...
6 @2 E# g' i; j; b1 Gprint 与 printf 的差别是在於 format, printf 的引数比 print4 {; j& {0 d8 c1 [
多了字串 format。format 的型式与 ANSI C 的 printf 之格式相同。% c t$ Z+ }) ]' H+ [+ v1 w
printf 并不会做自动换行的动作。内建变数 OFS 与 ORS 对 printf 叙
* l8 ~: I5 }) S; s5 _$ K1 v! Q述没有任何影响。
5 E8 l. u* g; P8 p格式的指定以字元'%'开始,後面接著格式控制字母。
( N+ t5 t9 @" d! _1 H+ d格式控制字母如下所示:% h6 Y5 `( V3 ^8 X1 J
'c' 将数字以 ASCII 字元印出。
4 c# C. D' F5 o8 p* c3 O例如'printf "%C",65'会印出字元'A'。
) ^ @( V& K1 e'd' 印出十进位的整数。6 A; ^! r" g0 h) m7 C+ ?
'i' 印出十进位的整数。' i6 J+ F7 g$ n+ _* x
'e' 将数字以科学符号的形式印出。9 f' }& h0 x- Z& B
例如( c; M K2 U* N/ k' }. ]: s1 i
print "$4.3e",1950
0 t: m" Z5 E2 ^: h9 x' m8 U# U% R结果会印出'1.950e+03'。
; w0 ~4 F9 r/ I5 [7 }'f' 将数字以浮点的形式印出。; }( M+ Z4 J2 R+ |/ ]' B
'g' 将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果
& |6 C$ f1 ^0 x8 x9 Z* z大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印
1 \% K: {% s; w出。
) W- z' H$ [$ \0 E! i'o' 印出无号的八进位整数。% `9 E0 w8 ~: N9 R5 b+ p
's' 印出一个字串。5 H3 k4 J& ^) e. O; e6 u
'x' 印出无号的十六进位整数。10至15以'a'至'f'表示。6 p! G* f- ^+ [% F- ]! m
'X' 印出无号的十六进位整数。10至15以'A'至'F"表示。2 v2 I+ G0 L( Z; f
'%' 它并不是真正的格式控制字母,'%%"将印出"%'。# |- V: M1 D- _) y
在 % 与格式控制字母之间可加入 modifier,modifier 是用来进一: c" N( _& F8 J8 n3 [
步控制输出的格式。可能的 modifier 如下所示:9 w7 n6 h( k( K, P9 q
'-' 使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在: w3 h4 X# ] M: V$ H8 ~
被指定的宽度向右靠齐。例如:
0 i( N- @4 K. yprintf "%-4S", "foo"
: [: D5 ?5 i& u$ f( V会印出'foo '。
6 \: K, h$ u0 d9 c7 l# F'width' 这一个数字指示相对应的栏位印出时的宽度。例如:% N* J' y" b* K7 C0 x) M% P( Q; ~
printf "%4s","foo"
9 h5 B! j' {8 K. H* v. E/ h9 n会印出' foo'。9 p- p/ p) F* P( j: ^
width 的值是一个最小宽度而非最大宽度。如果一个 item 的
! }/ y0 l& R3 I值需要的宽度比 width 大,则不受 width 的影响。例如* [5 O1 |- s! ?6 X- b o
printf "%4s","foobar"
3 j3 E+ M& [. J将印出'foobar'。
; [2 x( O2 X" K'.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。如3 ~* Q7 d5 t9 ^, C6 q+ q0 Z B; _
果是要印出一个字串,它指定此字串最多会被印出多少个字$ G" H& ^3 G9 l8 x
元。9 P: s# r1 g. r/ w1 W
' j6 W' V" A# o
第五章 patterns
. M0 ^7 O# S. f% H$ Z在 gawk 程式里面,当 pattern 符合现在的输入记录(record),其$ @6 p) a& J8 H! t8 w* ]
相对应的 action 才会被执行。
! {) s1 U" t7 w7 k" y( w* [
4 c" O' S. ^- Y- K$ M3 a5.1 Pattern的种类
) M8 C8 O( z. D9 ~/ O6 Q$ H( G$ L这里对 gawk 的各种 pattern 型式作一整理:
0 U" z1 y: c$ w& i6 Q5 V/regular expression/
Y- ^) J/ R. |; Y一个 regular expression 当作一个 pattern。每当输入记录 (
+ r$ `; r* b/ K* Yrecord)含有 regular expression 就视为符合。& H* \ U5 N v- C. p. q2 ]
expression
: Y r- ~5 a0 u) r$ P4 j; Y一个单一的 expression。当一个值不为 0 或一个字串不是空的,- V& [& V% M0 i" s
则可视为符合。
! o5 s8 p" B+ w6 m ypat1,pat2
6 o8 B4 _ E0 x# R1 T一对的 patterns 以逗号分开,指定记录的□围。
4 Q1 M/ v' J2 T" G5 CBEGIN; O2 L! Y5 |% U( c2 U; R
END/ ^( y/ r% L5 S5 B$ v
这是特别的 pattern, gawk 在开始执行或要结束时会分别执行相
: R" O. A! @8 t# |$ m3 x对应於BEGIN或END的 action。
a- z6 J# T9 Anull
' \2 J& C7 j, t0 i( i这是一个空的pattern,对於每个输入记录皆视为符合pattern。
1 J% E- W9 Q- z% u5 }2 i5 E0 o( i. y/ y1 V* S6 F; g- n
5.2 Regular Expressions当作Patterns9 P7 {! z; {) J& z! B9 h+ r
一个 regular expression 可简写为 regexp,是一种描述字串的方7 }# r7 F0 d) Y, Y. T! W
法。一个 regular expression 以斜线('/')包围当作 gawk 的 pattern。; m! d$ D4 ^- H
如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,
1 }) s3 N; q1 L6 D2 a" |4 N对於任何输入记录含有'foo'则视为符合。 r* Z$ T' t5 Q' a+ n3 Z2 S
下面的例子会将含有'foo'的输入记录之第2个栏位印出。4 {* i% L7 J' W9 L
gawk '/foo/ {print $2}' BBS-list) U% ?# f1 d4 \' e) T
结果如下:- v) j j4 |5 Z/ p6 r, a$ Q
555-12340 q a0 I2 J {9 U2 x) h, g; d" a
555-6699
7 w/ x5 u! w& J# E% V( t555-6480
0 S3 c# d0 Z2 f+ C w9 k. q. N' ]555-2127
, h. t2 V6 y: I4 Rregexp 也能使用在比较的算式。
5 I% M! T" A; Q3 G6 K/ aexp ~ /regexp/
' S2 o7 s2 ]% N9 s; Y6 W6 O如果 exp 符合 regexp,则结果为真(true)。: z& q+ D: m! w
exp !~ /regexp/
. w8 \& P3 Z2 m' k2 J如果 exp 不符合 regexp,则结果为真。8 C) f9 p* H6 U: I
% W$ p" W. t8 s% g' i. g
5.3 比较的算式当作Patterns
4 l% v, J# h1 ]. U9 `比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於% H. z! X9 g3 Y. m
、小於。下面列出一些比较的pattern:; M* g# z! \+ C5 ?3 C
x<y 如果 x 小於 y,则结果为真。
* r0 k& C' J- fx<=y 如果 x 小於、等於 y,则结果为真。8 m o' D3 y. ~& p- i) d- C0 R
x>y 如果 x 大於 y,则结果为真。
/ a f* n" z9 y" I/ ]( Yx>=y 如果 x 大於、等於 y,则结果为真。
5 Y0 p: H4 Z$ u) U2 L {x==y 如果 x 等於 y,则结果为真。% e$ z: g' }) y2 ]$ j8 E
x!=y 如果 x 不等於 y,则结果为真。+ a/ {' T* |" W6 ~0 r
x~y 如果 x 符合 regular expression y,则结果为真。
( D- s* K4 r" Z* z: ]8 qx!~y 如果 x 不符合 regular expression y,则结果为真。2 R% X* V% H& r% ^5 d( G) S/ k
上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,- S5 s. Y2 c/ Q5 C' _/ f- x
否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,
7 L1 `& ?) u: c会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同! s2 K8 u0 [/ ^, k0 |; y5 b
的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视5 y* l/ F. r5 j+ P
为长的字串比短的字串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。6 L$ r" T8 a5 ]$ p) L
, `& s. k+ j U9 O5 C5 `" X* p8 P* g
5.4 使用布林运算的Patterns
2 q4 }. \! H0 y6 J一个布林(boolean) pattern 是使用布林运算"或"('||'),"及"
& ?) ^' \% j* D K('&&'),"反"('!')来组合其它的pattern。
& a0 J* o8 W8 {; y! ]3 i例如:8 O9 k( d3 H6 {4 t% f/ v1 T
gawk '/2400/ && /foo/' BBS-list
: \6 \4 o# d; s* v/ P# ]gawk '/2400/ || /foo/' BBS-list8 {3 V, H2 D! u
gawk '! /foo/' BBS-list
( w0 O: p4 ]& W, p( Q- z1 q$ F3 k2 X% f3 ~1 z# @; o
第六章 算式(Expression)作为Actions的叙述
+ d/ J- }7 c5 d: f9 ^2 X! X算式(Expression) 是gawk程式里面action的基本构成者。
1 c: A; O; P9 j. u3 _6 g5 M5 J4 ~
1 C- I1 p: x0 y6.1 算术运算8 \( T% C& [$ d) a4 T
gawk 里的算术运算如下所示:
" M9 ~' r! T2 C Y* |3 N; |. ~- f, @x+y 加5 w+ B& P( a6 }3 Q2 V+ P2 o
x-y 减1 p6 w( Z6 z) J4 z
-x 负! I y- ^; O1 ]1 h( J
+x 正。实际上没有任何影响。
+ x# G' G& |. A; d! kx*y 乘
1 c& U4 L3 }: i0 zx/y 除" S9 T( `' b) f; Z. Q
x%y 求馀数。例如 5%3=2。
- B o8 _$ }1 f! gx^y
/ s$ p: ~' i9 S5 g2 r' S4 h7 h1 H8 V" rx**y x 的 y 次方。例如2^3=8。
, f a) D. Z# g6 ]! P% h5 D% A& e U/ F% K2 ?/ t' @+ |$ |
6.2 比较算式与布林算式) E1 s$ h- A$ j$ h- ]( R A
比较算式 (comparison expression) 用来比较字串或数字的关系0 L1 o9 s0 {( ?. ]0 p
,运算符号与 C 语言相同。表列如下:
0 t; W1 ~: w' C( D. F2 B$ f1 Xx<y
- c i+ }% M) p; j# J) Mx<=y
$ N1 _8 K* t; |2 C; j1 ax>y9 I4 H/ m% ^6 n4 o0 t J& [
x>=y2 K2 w( b% N# h* x, \
x==y
: ?, n% p& i3 r& h1 E! O! Sx!=y. H0 X5 Z3 l8 d, E
x~y6 H: A; p; Y! i9 J1 t0 y5 c4 X
x!~y
4 w5 a' Y) U; [) l! C比较的结果为真(true)则其值是 1。否则其值是 0。
) M& W. h o( g0 A布林算式(boolean expression)有下面三种:
4 ~8 b0 k- R( J- Dboolean1 && boolean2- U! N4 A( L9 Z- s1 F r- E& c3 i$ M
boolean1 || boolean2
+ A/ b1 p% X c8 n5 e7 a! Q' E7 q! boolean
: F9 x( ~+ {! a/ Z- g7 D
/ q6 m, [9 } O, S" O6.3 条件算式(Conditional Expressions)
# h5 {* l1 p* m( c; _, L一个条件式算式是一种特别的算式,它含有3个运算元。1 o% i8 L3 Y8 Q" R
条件式算式与C语言的相同:: o q7 M. t2 ^# Z, {8 N
selector ? if-true-exp : if-false-exp
5 }' g9 J, ]8 Q; @它有3个子算式。第一个子算式selector 首先会被计算。如果是真,! b2 j! I& U. W* T
则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-' E& s' l6 m j
exp 会被计算且它的值变成整个算式的值。( J% u1 a+ |7 q. T( f3 `% M
例如下面的例子会产生x的绝对值:
8 h9 g: N+ ]% ~. ~, Ix>0 ? x : -x( r* q( X/ V: F' N( U: b1 p& t9 _
: d1 }$ k4 A, s. [第七章 Actions里面的控制叙述
- E% f- `$ j, F) ^4 ~& Q* `$ E在 gawk 程式里面,控制叙述诸如 if、while 等控制程式执行的流( f4 B$ b$ k: U& R
程。在 gawk 里的控制叙述与 C 的类似。8 Z' p5 O2 d1 |& S
很多的控制叙述会包括其它的叙述,被包括的叙述称为 body。假
2 [+ O2 l9 n. M如 body 里面包括一个以上的叙述,必须以大括弧 { } 将这些叙述括起
* u m' [# [3 U来,而各个叙述之间需以换行(newline)或分号隔开。
/ e2 ^% w' q1 F1 w9 w0 D. b. f& G$ J% g. o* C6 x
7.1 if 叙述$ l* [! L W* \$ B" `9 `$ b- w
if (condition) then-body [else else-body]
; Y) S* Q S* N( m2 I0 m- q如果 condition 为真(true),则执行 then-body,否则执行 else-body。
9 \: Y# G: x# `' y, x' @举一个例子如下:1 q- A/ V; ^& `* F! x
if (x % 2 == 0)
/ e4 `1 A! Y9 h8 _print "x is even") r. V/ S; l+ r+ o$ z
else7 z& E/ l& J0 k# _6 ]* ^! `- @3 `6 F
print "x is odd"1 F, G, W' w k1 Q! C
6 }. c7 h) T& u! ~
7.2 while 叙述
! \+ a, M' k& I7 ewhile (condition)' J" y9 Z9 y" Z$ p( J
body
+ a8 p" }6 ]0 X8 e7 b* a1 wwhile 叙述做的第一件事就是测试 condition。假如 condition 为真则
( a; h7 O% b9 l( ~8 q0 @8 T9 j执行 body 的叙述。body 的叙述执行完後,会再测试 condition,假如
2 F# k. y/ D; rcondition 为真,则 body 会再度被执行。这个过程会一直被重复直到1 _: |7 P7 V- `. z! p
condition 不再是真。如果 condition 第一次测试就是伪(false),则
3 m5 t3 L# m& C& \+ Obody 从没有被执行。; W e( O) f, x$ d7 a7 n# p# W
下面的例子会印出每个输入记录(record)的前三个栏位。: V3 L( |7 B( j! f
gawk '{ i=1
& W+ m V! ? i" {( f& e; Qwhile (i <= 3) {. G* l: k+ _# K+ |
print $i
$ ^" Q: w- F3 ~* a( ^i++
; B/ l# t( w6 x$ Y# i/ y}. k2 @5 B( m3 ^5 k
}'
7 x+ X9 D8 b3 `% I! W" i2 K# ?3 c1 q8 I5 @6 ^2 Z
7.3 do-while 叙述9 B" N1 d) _ Z% M
do
/ {# R7 I) I1 C* M3 [body+ e2 J0 H9 a4 u# t
while (condition). i% C+ {7 ]& H5 d2 a# T
这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。: e: |4 A- `' o( e
即使开始时 condition 是伪,body 也会被执行一次。
0 r, f' ~7 J# Z# l下面的例子会印出每个输入记录十次。
! X: a' L* X0 b5 X( H7 ugawk '{ i= 10 X; r8 i; P/ V/ j `/ y
do {
1 B8 E: l; f2 U/ ^print $0$ T3 Q( x3 D' H$ r
i++: H/ {) z: t& Z$ w2 }; a4 `
} while (i <= 10)
) W4 a; r5 t# P0 n% y; v6 W7 V# e}'
9 @( W' K3 |( {$ A7 t* b/ A! m$ ^; H
7.4 for 叙述 S2 L5 e0 g" k# h& E
for (initialization; condition; increment)& f2 l5 z( ~) C+ w
body
$ p9 q& i3 x4 @9 X7 a此叙述开始时会执行initialization,然後只要 condition是真,它
. ]$ O0 b6 \0 ]" w. w会重复执行body与做increment 。$ A g; _/ M9 `* Y' r
下面的例子会印出每个输入记录的前三个栏位。
3 i& i9 c+ Z1 w8 K& v4 A' ? Q2 Hgawk '{ for (i=1; i<=3; i++)
1 n+ C* v0 W. x, h! y& Vprint $i% G# O6 v- ]* z# n5 o$ r: e' j
}'; h+ P1 O7 i: O- {* F
# ?% H, K6 T x9 j$ \3 D7.5 break 叙述0 S' P) N9 L( s# Z. d
break 叙述会跳出包含它的 for、while、do-while 回圈的最内层。* X: J; N: ~0 |' n# V/ v$ ^1 }7 B
下面的例子会找出任何整数的最小除数,它也会判断是否为质数。
3 O4 E5 u z8 X) a/ Xgawk '# find smallest divisor of num
1 R* H/ g! F1 c) B V{ num=$1! t. H! z, H ^1 s* K
for (div=2; div*div <=num; div++)' K$ _$ k, A8 C! U3 O
if (num % div == 0)
( O" n# U) ]0 Y Y; Obreak
0 V% [" G3 @$ m4 T: Iif (num % div == 0)$ J0 O6 d5 @8 C+ g- E4 X# n
printf "Smallest divisor of %d is %d\n", num, div: h0 x! u5 `0 i
else7 R" ?) E3 z0 [9 o9 G! E* M" @
printf "%d is prime\n", num }'
- d# @" [+ u. d* D: L' M9 M6 ~3 ~5 T. o v' c% p! [* y
7.6 continue 叙述
7 A) {* k3 q) L- Fcontinue 叙述使用於 for、while、do-while 回圈内部,它会跳
6 [5 M: c* {9 @4 ?9 l% H: h3 y" M过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。 x) n8 B6 {7 X/ ]! U) H
下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。7 u! M% n2 ?2 f3 C9 E& T' C
gawk 'BEGIN {
: m* r! D( P6 Pfor (x=0; x<=20; x++) {4 g2 z5 i* }: {4 Q+ M; G6 d
if (x==5)
( p' |: p6 ?. ~& V# k, @continue; z _1 u/ L: p8 C) L& T4 b/ P9 J
printf ("%d",x)
1 k& v4 O( Q2 q! e6 M# T% _) P' H}
& T9 {: g+ \+ c5 Lprint ""3 B, N( L% {; l% [" i7 j2 M/ k
}'( U5 ?/ E: W& F+ O5 q. y
9 F% Q$ T; H4 O6 w2 R
7.7 next 叙述、next file 叙述、exit 叙述0 l0 l: F# q, y" B0 B
next 叙述强迫 gawk 立刻停止处理目前的记录(record)而继续下一
0 K* L9 Y/ B3 A0 h个记录。4 e0 y( @& @, J) ^0 M" ]8 L0 G" c) R( W
next file 叙述类似 next。然而,它强迫 gawk 立刻停止处理目前
$ d+ i5 @- ~# `/ v的资料档。
# y. ~: ~5 u1 sexit 叙述会使得 gawk 程式停止执行而跳出。然而,如果 END 出现
$ w3 ]7 C+ w. t,它会去执行 END 的 actions。+ m0 J1 z4 ^" {5 v
' M: E5 d5 k! Y+ G, s第八章 内建函式(Built-in Functions)
0 b* x# P6 q9 l. x内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建7 v2 `1 S- U! _) I- D/ ~
函式。/ C, E" L& F8 {/ w7 ~
# R/ V, t: X! e: f: ^! m' W' f# h8.1 数值方面的内建函式
' I r. X7 _7 {int(x) 求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9) V7 T# `5 ~ S% c0 H
是 3,int(-3.9) 是 -3。6 g' `, Y" C7 X$ _% Z' f
sqrt(x) 求出 x 正的平方根值。例 sqrt(4)=2
+ z5 b0 x4 [3 ^- w% O# @) Zexp(x) 求出 x 的次方。例 exp(2) 即是求 e*e 。! c- M" _, A8 E2 F# R
log(x) 求出 x 的自然对数。
2 E9 S4 u; l+ i$ {sin(x) 求出 x 的 sine 值,x 是弪度量。' T, I2 M# Q/ f6 _
cos(x) 求出 x 的 cosine 值,x 是弪度量。; Q; s. ?+ g3 h% Y% j M
atan2(y,x) 求 y/x 的 arctangent 值,所求出的值其单位是弪度量。
" y% q' t& r$ z6 a$ [5 orand() 得出一个乱数值。此乱数值平均分布在 0 和 1 之间。这个
) P' r6 o5 p: ^3 P5 q" m$ s' x值不会是 0,也不会是 1。) ^ J* _& o8 ` t: t8 `
每次执行 gawk,rand 开始产生数字从相同点或 seed。' j" K/ w: F: Y5 e1 e( a
srand(x) 设定产生乱数的开始点或 seed 为 x。如果在第二次你设
9 S; A8 [+ R7 J5 Z( R' R3 `定相同的 seed 值,你将再度得到相同序列的乱数值。
) p+ l5 b7 v3 p$ F; M如果省略引数 x,例如 srand(),则现在的日期、时间会
( v. H0 `' x$ b# h/ b被当成 seed。这个方法可使得乱数值是真正不可预测的。" T2 R# }3 Y5 R
srand 的传回值(return value)是前次所设定的 seed 值。
& N/ V. @6 P8 u0 t
, z" U5 f) U; Z( `- O8.2 字串方面的内建函式
; [( b$ r& b) `1 yindex(in, find)
9 _# p1 c" J6 i2 l- f它会在字串 in 里面,寻找字串 find 第一次出现的地方,传回值是
, Y- U' H- a& n) {$ g9 \) r& @字串 find 出现在字串 in 里面的位置。如果在字串 in 里面找不到字8 d8 g% k. n! B& Q8 G* s
串 find,则传回值为 0。
( f/ b0 E" }+ M例如:5 z! T6 b2 W7 Z. Y" v% s
print index("peanut","an")
/ T# M' }' O% |7 a会印出 3。
, }, e. |2 C$ {! V/ ^length(string)! T& {4 W9 a; _! O* F; I
求出 string 有几个字元。
6 p F5 P' |2 J, R3 |$ i例如:
/ i; |' ?5 R9 m5 I- blength("abcde")1 i% W! Y, i: |/ B, L
是 5。" {, ?) j- ^ f0 s5 ]
match(string,regexp)9 ^- D' K0 V& _, R# N& t2 X
match 函式会在字串 string 里面,寻找符合 regexp 的最长、最靠9 ^% ?. q8 e& e8 C
左边的子字串。传回值是 regexp 在 string 的开始位置,即 index6 D7 Y. @- @$ n6 d$ t! V% u
值。
8 n% @6 d- I% u3 T8 ematch 函式会设定内在变数 RSTART 等於 index,它也会设定内在变
5 N% d, [ P# c数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为% G, r$ y5 p6 u/ [
0、RLENGTH 为 -1。
( ]& N% j* F6 v: w+ x+ Msprintf(format,expression1,...)& _# z3 U! W- X; L
举 printf 类似,但是 sprintf 并不印出,而是传回字串。
0 G8 F$ s+ ]! Y- E, v8 R4 f, v/ d例如:5 {5 v$ J9 T" F; a0 |" h: }
sprintf("pi = %.2f (approx.)',22/7)
+ Q( e3 |2 m3 Z/ h8 ]传回的字串为"pi = 3.14 (approx.)"6 n! u j/ I0 Q2 L+ R
sub(regexp, replacement,target)+ Q1 H0 G1 K, l
在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,
. K W, ~( S+ `以字串 replacement 代替最左边的 regexp。
* v% E1 x1 W$ V- A9 H% i例如:' M8 u3 V$ t( G6 h2 C
str = "water, water, everywhere"% S6 w# O$ @: r
sub(/at/, "ith",str). ?! u9 ~8 @$ }& \
结果字串str会变成
7 T) R7 W+ |( u ^* S"wither, water, everywhere"3 w4 Z" P) j/ h9 \- i1 `: d
gsub(regexp, replacement, target), Y) h5 _1 T# @3 }
gsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的4 V* V+ y& {* M i% q3 F
所有地方,以字串 replacement 代替所有的 regexp。
5 R* w$ g: i: R- F( n& Z例如:
, F i5 Z4 o& ]; ^6 L6 h0 nstr="water, water, everywhere"
/ e$ F9 |5 J7 w8 S6 A: a- }gsub(/at/, "ith",str)
9 [4 ]* b2 F! X结果字串str会变成6 p& c, m* v l" b3 B
'wither, wither, everywhere"- O3 g& u4 ?! o
substr(string, start, length)' w1 p2 X0 ^6 y1 G w: C
传回字串 string 的子字串,这个子字串的长度为 length 个字元,0 L2 O/ m) k/ y4 Q3 F& ~. Q! ~
从第 start 个位置开始。
8 H+ A* T/ `1 f x9 v2 v# k) u. O( m例如:
- I2 v* p& m/ u* y: usubstr("washington",5,3)
7 P) D# v: Y+ R# L. t5 h& m传回值为"ing"
6 P- B& k/ j% e Z% o如果 length 没有出现,则传回的子字串是从第 start 个位置开始
" ^* V) j) D, J0 i+ r3 Y) g至结束。9 L: t$ i" P7 K3 n; K/ l& o
例如:
4 C' a8 s! ]8 v x: [* Dsubstr("washington",5)+ P% R) g5 G+ d* V N. N; e
传回值为"ington"
! q0 P2 C: m) z+ @tolower(string)8 c/ }: Q9 T% i L. X/ c
将字串string的大写字母改为小写字母。
7 }6 }9 X1 W% r: c/ ^5 C" H. {例如:6 [: C. `; T [. h" c" ~
tolower("MiXeD cAsE 123"): A6 ]) {" {3 H R2 y7 R6 K
传回值为"mixed case 123"
# L4 U! T% M; I, \2 ctoupper(string)% ]" H, H6 N$ j/ B; C3 T2 S5 n
将字串string的小写字母改为大写字母。
- X2 A% \. T U. ]) T8 Q) `例如:" Z* u5 V) I' Q$ r3 p
toupper("MiXeD cAsE 123")+ H0 b/ g% o' r' S' z
传回值为"MIXED CASE 123"
$ s) @, C2 D& e3 b6 Z' P* O- Q3 {/ y' R. G
8.3 输入输出的内建函式0 M% [7 }' P' ?4 o" U$ c# F0 R
close(filename)% ] s! J6 x. Z2 W2 d! I
将输入或输出的档案 filename 关闭。
- ?4 N, P/ J. E4 B7 h1 H: Z, _system(command)
i4 j {3 t( E1 A) s2 z. [此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk8 e4 I v8 y5 B# A2 b7 x q
程式。: K5 N3 Z) r5 n3 @
例如:, h) X8 o! _+ c( x, G7 m+ \# ~1 F) |
BEGIN {system("ls")}
( `) Q) g9 j+ i& e% A$ k
6 [ p0 [5 E' s( }' V Y第九章 使用者定义的函式(User-defined Functions)
* i3 I" O3 a( `9 i( \复杂的 gawk 程式常常可以使用自己定义的函式来简化。呼叫使用, s' P/ v. P, X
者定义的函式与呼叫内建函式的方法一样。3 k7 W4 B/ ^6 j0 G
$ H- N2 }1 c' V* a6 o, q+ w# I2 O; C
9.1 函式定义的格式
% Y5 I+ s% |! J. }( k: ^函式的定义可以放在 gawk 程式的任何地方。8 t- h! q0 K+ f0 s
一个使用者定义的函式其格式如下:% V) R }( Y# l2 j1 Z8 |0 ^
function name (parameter-list) {
+ L; G4 B% |3 k) ]3 I% u. Bbody-of-function' t" w% J9 `9 s" i4 w6 Y4 R1 J
}. ]. j7 n, |1 i( L
name 是所定义的函式之名称。一个正确的函式名称可包括一序列的字
3 N* ~/ g( U" `3 V2 x- H, [ [母、数字、下标线 (underscores),但是不可用数字做开头。( I. P; E. v; N2 D+ j4 Y
parameter-list 是列出函式的全部引数(argument),各个引数之8 X6 g: {/ L6 s
间以逗点隔开。
5 P+ B) c: x# a0 D( ?' l6 @body-of-function 包含 gawk 的叙述 (statement)。它是函式定义
, B0 M& u) r4 k3 l# A# c' h里最重要的部份,它决定函式实际要做何种事。3 s4 C1 s7 |/ N6 T" W# _6 \
+ q+ {% [/ p1 o9.2 函式定义的例子
& g2 e1 Z* l0 n$ ] c* y. O8 S+ P2 _- c下面这个例子,会将每个记录的第一个栏位之值的平方与第二个+ c! p5 R+ i' o& a
栏位之值的平方加起来。
! @ H0 |' ^( M9 U{print "sum =",SquareSum($1,$2)}
% J7 J$ F' r3 G4 G$ qfunction SquareSum(x,y) {
& r; K H) ~7 A2 T; x6 w# a2 T9 m+ wsum=x*x+y*y a* L" x- ~( E
return sum& \/ O1 N5 ]/ r5 o# j1 M7 |
}
' L" w# @: }: ~: R, W
6 c9 S- k* @4 c) U& s7 Z第十章 □例0 B/ ^2 e) {; r1 `: ]+ l
这里将列出 gawk 程式的一些例子。
$ Y( S7 q" Z" P5 bgawk '{if (NF > max) max = NF}4 L6 R6 q4 s; V& N4 b
END {print max}'
' r5 d5 n# N& J5 ]* v! r此程式会印出所有输入行之中,栏位的最大个数。2 F9 _" k1 o6 @1 k: h! t( p8 {7 X; ` X( Z
gawk 'length($0) > 80' k6 a7 Q" n, f4 ~% w0 V8 D, ]0 \
此程式会印出一行超过 80 个字元的每一行。此处只有 pattern 被
; r4 b. ?" d+ g6 O/ |列出,action 是采用内定的 print。
$ B8 i! f7 p4 n/ S! y- P! d+ Bgawk 'NF > 0'
5 Y, z+ A2 {* T0 b对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
( |4 G1 b# |! j% [3 G% R单的方法,将一个档案里的所有空白行删除。/ n/ Y5 ]% N' N g
gawk '{if (NF > 0) print}'6 B, w" g& { S
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
& U3 M, G; }2 d% Y* k) t/ {- l单的方法,将一个档案里的所有空白行删除。
l+ [3 d) |1 _gawk 'BEGIN {for (i = 1; i <= 7; i++)( @* C7 C6 n( B* _% x
print int(101 * rand())}'
3 k7 U" E% j# U4 y$ @6 H此程式会印出□围是 0 到 100 之间的 7 个乱数值。: l) b$ B- I* {9 c9 |& R! @. a- A i/ X
ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
0 s: X: H, \" U5 c: e此程式会印出所有指定的档案之bytes数目的总和。/ I. G/ e6 {! |1 l% F. R
expand file | gawk '{if (x < length()) x = length()}0 p) B& z: ~. ?. r3 V
END {print "maximum line length is " x}'
% l: x4 [. `3 U3 ?此程式会将指定档案里最长一行的长度印出。expand 会将 tab 改& o' q" X7 W2 S5 _% K, @
成 space,所以是用实际的右边界来做长度的比较。
$ u3 @" c% ?/ {/ ^: I- p! Mgawk 'BEGIN {FS = ":"}
- L0 l' I2 }# w- ~# y' w/ ~{print $1 | "sort"}' /etc/passwd" z1 U4 X# G( \
此程式会将所有使用者的login名称,依照字母的顺序印出。2 B" H0 J r' _; N! V' g. X9 g1 v$ i
gawk '{nlines++}
9 P! w( T) P6 D# fEND {print nlines}'
6 W$ a1 }. m" `, p& W6 g此程式会将一个档案的总行数印出。' @" z: F2 ~. F+ l
gawk 'END {print NR}'
6 C7 o; l: F# p2 W8 k4 Q. |+ z此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk
) O+ D1 H+ ^# }+ g8 R来做。6 z" p# Z8 A1 G, h- [% N" B
gawk '{print NR,$0}'4 }) Y) J3 M' L8 j% J, N+ \- s
此程式印出档案的内容时,会在每行的最前面印出行号,它的功
' g$ M! r% w6 z! B: O能与 'cat -n' 类似。
& n: B5 \0 K# A! m3 A) U9 _' n5 [* o! Z! A; y; r2 U6 y
第十一章 结论: R/ W, F3 E. V1 H( _
gawk 对於资料的处理具有很强的功能。它能够以很短的程式完成9 ]* s ^. P3 \+ R7 W! a$ H5 N
想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件
7 D6 c7 L. S$ e j* Q& m5 {工作,以 gawk 程式来写会比用其它程式语言来写短很多。. k- ] E- _1 a) Z
gawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使7 a7 \; |/ R/ H% r( v
用。 |
|