TA的每日心情 | 奋斗 2019-2-12 09:32 |
|---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到 累计签到:1 天 连续签到:1 天
|
马上加入,结交更多好友,共享更多资料,让你轻松玩转电力研学社区!
您需要 登录 才可以下载或查看,没有账号?立即加入
×
GAWK
2 s& C/ d Z' R0 {# G第一章 前言5 w2 L$ @8 [+ y( t
第二章 简介
9 o: ~( ?: E, c) L$ J5 w第三章 读取输入档案: M; c, H p/ D4 }% A. S, N- U
第四章 印出
5 N, U- u7 R- {第五章 Patterns
/ K9 ?8 H0 |$ ~& P) V: N第六章 算式(Expression)作为Actions的叙述
2 N2 `; [! {9 C( U第七章 Actions里面的控制叙述: ^1 y5 N2 m- d8 f* f
第八章 内建函式(Built-in Functions); }8 ]6 N% ` E- x+ w
第九章 使用者定义的函式5 p2 @# |! T& b, u6 g, w' a
第十章 □例* Z2 b$ ^4 s5 X% t i" g7 m
第十一章 结论
! L% I! Y. B9 w" _$ c, G/ ~/ d/ \/ I5 h& @4 u& B
=======================================( `: _6 V1 u4 p
第一章 前言
9 }2 \* ^" g$ l; S( ]awk 是一个程式语言,对於资料的处理具有很强的功能。对於文3 s2 t- \, z- d2 d3 V
字档里的资料做修改、比对、抽取等的处理,awk 能够以很短的程式8 Q! \" W. X9 }1 P5 H3 P
轻易地完成。如果使用 C 或 Pascal 等语言写程式完成上述的动作,+ f3 `1 c9 Y, m* I! B$ w& E4 {8 l
会不方便且很花费时间,所写的程式也会很大。
4 K. g+ @2 I5 j# Q1 m+ o# C q |8 Aawk 能够依照使用者的定义格式来分解输入资料,也可依照使用
5 O$ Y: c! J' k- Y/ c0 J/ [者定义的格式来印出资料。1 t3 H. [" R0 s6 b' t' M* F
awk 名称的由来是由它的原始设计者的姓氏之第一个字母而命名
5 M. e0 E% s, f/ Z:Alfred V. Aho, Peter J. Weinberger, Brian W. Kernighan。
; T2 M# o' L" V ?% T; t) ~+ {$ p; Vawk最初在1977年完成。一个新版本的awk在1985年被发表,它的功能: I5 y+ a9 [1 d9 ~
比旧版本增强不少。
( x$ J" {2 q( J; e7 [& \; b0 \' w0 \7 s' {gawk 是GNU所做的 awk,gawk 最初在1986年完成,之後不断地/ x1 v3 a* v' P# `. L5 o
被改进、更新。gawk 包含 awk 的所有功能。/ _, }, o- P. J* a
往後的 gawk 将以下面的2个输入档案来做例子说明。! |! b! Y# [* u) ~ |' K3 S
档案'BBS-list':
8 O: t+ o) n- w2 w/ k. i( n5 f# jaardvark 555-5553 1200/300 B* D1 C. w0 M6 w# P2 a8 a
alpo-net 555-3412 2400/1200/300 A% ]9 j# e+ Q) R* c- a
barfly 555-7685 1200/300 A$ ]& g0 U4 A- z4 a0 V
bites 555-1675 2400/1200/300 A6 i4 X' v7 E, V
camelot 555-0542 300 C
9 W* k8 r9 F& ^/ p7 jcore 555-2912 1200/300 C
8 }2 o+ ~: t2 i x2 dfooey 555-1234 2400/1200/300 B
9 o9 X7 X( n1 gfoot 555-6699 1200/300 B- }& J0 c% N( V& @
macfoo 555-6480 1200/300 A
: L/ C5 f# H& u0 Q' Asdace 555-3430 2400/1200/300 A
, f2 }# r; c5 \- qsabafoo 555-2127 1200/300 C
p6 j: U/ D8 U% b& m! Q3 W) b档案'shipped':
# _8 d5 p0 h" ^- [ JJan 13 25 15 115
' I0 Q$ ?+ o. W# `/ BFeb 15 32 24 226
8 D' p; B/ v" P6 TMar 15 24 34 228: a" h+ P. C$ S8 {& j# c
Apr 31 52 63 420
. C( W9 O+ }; n4 _* xMay 16 34 29 208
# T, B3 [4 K) q6 t: |Jun 31 42 75 4922 T( i7 u. ?# z, x/ }' X+ @
Jul 24 34 67 436
+ M/ r) ]5 | k/ q5 u* GAug 15 34 47 316
' |/ [$ j+ b! x# }1 ~2 }" S" PSep 13 55 37 277
0 G1 V" a. Z5 n2 tOct 29 54 68 525& u: v6 \* @7 W1 D
Nov 20 87 82 577
3 V: N8 u, H) Z qDec 17 35 61 401& v3 j/ W2 C* {* v
Jan 21 36 64 620
5 D" m4 u: G1 b% [Feb 26 58 80 652" j8 K! u9 L1 Y9 A9 K" V
Mar 24 75 70 495: j. r1 ]' S z3 p: q
Apr 21 70 74 5146 Z1 u$ l2 m2 ^# v
7 d, X. y: K. W
第二章 简介8 Y: G; c, p3 V# ?
gawk 的主要功能是针对档案的每一行(line)搜寻指定的 patterns
& q1 l3 ?* g! Q, @7 c m# w/ ~。当一行里有符合指定的 patterns,gawk 就会在此一行执行被指定
& N5 U7 Q* P: n; F; H, o的 actions。 gawk 依此方式处理输入档案的每一行直到输入档案结) e/ Y7 i/ Q" O+ O& p! I8 F! D
束。
; S; E# P4 m9 Kgawk 程式是由很多的 pattern 与 action 所组成,action 写在- X6 m3 h/ {# {
大括号 { } 里面,一个pattern後面就跟著一个action。整个 gawk 程8 ?# `! V. C$ b
式会像下面的样子:. ]. R6 ^- n; @/ i
pattern {action}/ m a. l3 Z) I! k9 N; t
pattern {action}
6 D" F# e* G& |0 u7 ]: H& c在 gawk 程式里面的规则,pattern 或 action 能够被省略,但
; x# j9 e) |. J- ^是两个不能同时被省略。如果 pattern 被省略,对於输入档里面的
6 t V) V2 d$ o2 O8 g2 `每一行,action 都会被执行。如果 action 被省略,内定的 action0 Y+ Q" m0 \3 a1 Q! @1 i
则会印出所有符合 pattern 的输入行。
* q7 a8 O3 L: i
% d! f* a7 ^; W/ S" w2 Q) q) p2.1 如何执行gawk程式. G& _" Q3 y8 L7 A
基本上,有2个方法可以执行gawk程式。
% i) Q0 A- [' N7 Z' c7 ?□如果 gawk 程式很短,则 gawk 可以直接写在 command line,如下所示:
! s& ?8 y2 P7 h* \0 i- W7 _gawk 'program' input-file1 input-file2 ..." @- W! d5 v# P# G/ ~/ d$ w
其中 program 包括一些 pattern 和 action。" I- w# Z; G" X
□如果 gawk 程式较长,较为方便的做法是将 gawk 程式存在一个档案,
% B# g* |! k, g+ K9 n% }- l, N即 patterns 与 actions 写在档名为 program-file 的档案里面,执行7 t1 i" B) f+ J& c: X
gawk 的格式如下所示:
9 p2 V7 x0 [- U8 N6 |) j6 {/ rgawk -f program-file input-file1 input-file2 ...7 r, l- d( Q0 `2 A$ E+ b N
gawk 程式的档案不止一个时,执行gawk 的格式如下所示:
2 f+ Y0 a6 {2 X0 N+ Ggawk -f program-file1 -f program-file2 ... input-file1
$ \* g7 E, j3 W* r$ n' linput-file2 ...
8 |, _/ x5 t; I" F7 n% O' K* w8 f
2.2 一个简单的例子
" i% `& E" }" i+ |, x. a1 [% \现在我们举一个简单的例子,因为 gawk 程式很短,所以将 gawk 程' z& H# v0 ?$ l3 f$ \- J- {
式直接写在 command line。
6 Z1 }8 q0 q" w- v2 cgawk '/foo/ {print $0}' BBS-list
" a# l5 V9 B' i实际的 gawk 程式为 /foo/ {print $0}。/foo/ 为 pattern,意思为搜
/ F, C; Y( ?, f2 E寻输入档里的每一行是否含有子字串 'foo',如果含有 'foo' 则执行 action。 J: Q" z4 g3 z
action 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。! g' W6 Z: ?+ N: x: u
执行完上述指令後,会印出下面的结果:
+ D% g! X' `; Q5 _fooey 555-1234 2400/1200/300 B
( N! O# v( l2 d X# X( Cfoot 555-6699 1200/300 B' w# h' P2 _$ I- _( ?: v
macfoo 555-6480 1200/300 A& h( n k) g' z/ x6 ~* n9 m
sabafoo 555-2127 1200/300 C
4 a; ]5 P( ]' Z. R
( K. p" N# J- n- b. ?) ?" B2.3 一个较复杂的例子) ], k3 u4 i8 z3 t6 }
gawk '$1 == "Feb" {sum=$2+$3} END {print sum}' shipped
4 L2 F {: a6 l, o现在这个例子会将输入档 'shipped' 的第一个栏位与 "Feb" 做比较* K% U) \; u, ]1 D' @& V* E! ^
,如果相等,则其对应的第2栏位与第3栏位的值会被加到变数 sum。
; [2 w) V2 t1 f对於输入档的每一行重复上述的动作,直到输入档的每一行都被处理
3 e5 w9 R$ B6 D- ]过为止。最後将 sum 的值印出。END {print sum} 的意思为在所有的输
) @/ ]# f& t9 ?+ m入读完之後,执行一次 print sum 的动作,也就是把 sum 的值印出。
8 v) w2 K# H5 X0 U1 v下面是执行的结果:. E: c9 U0 z# }0 Q: t9 J" ^8 |8 m3 k
842 [9 ~& |* h1 i" T: L7 M
% E$ l( K. o( r) E$ t" d第三章 读取输入档案; C; J1 |- v# ^6 _$ `( e: Y
gawk的输入可以从标准输入或指定的档案里读取。输入的读取单% D2 D- i$ B3 T# u, ^: C
位被称为”记录”(records),gawk 在做处理时,是一个记录一个记
) d+ i; G$ P- w2 D' o1 f+ p c录地处理。每个记录的内定值是一行(line),一个记录又被分为多个
8 \9 S5 K" J& V" D" D栏位(fields)。. m. ^8 D# I9 q+ V
7 Q' V8 M+ A, J6 f, R0 d) |
3.1 如何将输入分解成记录(records)$ B4 m+ W. N0 q6 ^: C. l
gawk 语言会把输入分解成记录(record)。记录与记录之间是以
1 G0 }, R9 b4 Y8 Wrecord separator 隔开,record separator 的内定值是表示新一行的! R* `) S9 a, F! J* \' S
字元(newline character),因此内定的 record separator 使得文字/ o7 r4 ?; q# R
的每一行是一个记录。
, [9 ?2 {# j8 g; s3 B& I" Zrecord separator 随著内建变数 RS 的改变而改变。RS 是一个字串,4 B: Q+ x }, Y. v( Y5 i' W
它的内定值是"\n"。仅有 RS 的第一个字元是有效的,它被当作 record
0 D2 ?1 J! d7 Y- F$ e1 Fseparator,而 RS 的其它字元会被忽略。4 W& z! B: l; ?/ M X' W }
内建变数 FNR 会储存目前的输入档案已经被读取的记录之个数。内. |5 x! Y; Y. Q8 K: U7 }' p
建变数 NR 会储存目前为止所有的输入档案已经被读取的记录之个数。
$ T3 F! _2 N l: @$ [% [; H* M, N4 n
3.2 栏位(field) O$ J. E0 Y2 ?9 o# y
gawk 会自动将每个记录分解成多个栏位 (field)。类似於字在一$ t o" f# O! ~" F
行里面,gawk 的内定动作会认为栏位之间是以 whitespace 分开。在
! R1 }6 D6 f( d( K1 f2 r7 Z7 c, c" Ogawk 里,whitespace 的意思是一个或多个空白或 tabs。2 B# o' A' ^" H6 H, S$ `
在 gawk 程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位; X3 [5 X' l8 z4 N
,依此类推。举个例子,假设输入的一行如下所示:
4 v& Y7 f" N; k; {4 `) v2 g6 _This seems like a pretty nice example.
9 b8 E: f0 g2 f- D" x第一个栏位或 $1 是'This',第二个栏位或 $2 是 'seems',依此类推。
) Y3 d* D& E. y* x. o+ p* j4 e" Y有个地方值得特别注意,第七个栏位或 $7 是'example.'而非'example'。. ]1 D+ p# X; `+ t. s
不论有多少栏位,$NF 可用来表示一个记录的最後一个栏位。以6 m6 D) s! ]9 B* {) A
上面的例子为例,$NF 与 $7 相同,也就是'example.'。6 M5 b% J, o- J1 N0 {
NF 是一个内建变数,它的值表示目前这个记录之栏位的个数。
9 _5 x% g* f q6 y4 z$0,看起来好像是第零个栏位,它是一个特例,它表示整个记录。
( }( r+ k2 B4 k# Z7 t( e: v# O下面是一个较复杂的例子:- F4 z( X v' ~+ u5 Q
gawk '$1~/foo/ {print $0}' BBS-list7 a% M4 q( X/ D9 d7 j' y
结果如下:
/ O! x5 t; M/ X# _" K( b7 ~fooey 555-1234 2400/1200/300 B; [6 q- J' c$ e5 D& j
foot 555-6699 1200/300 B
( |4 ?% Y1 P# b" I) v9 \4 imacfoo 555-6480 1200/300 A
) X2 ~5 f; ?. b7 Y* R9 }: ksabafoo 555-2127 1200/300 C
6 Y, G2 i2 W9 z& O3 m* G" p1 W这个例子是把输入档'BBS-list'的每个记录的第一个栏位作检查,如6 A- C q2 u; O6 [
果它含有子字串'foo',则这一个记录会被印出。
- o9 S1 |3 D, }, j- F- F0 X3 u o4 r5 @% t% T
3.3 如何将记录分解成栏位
2 w# X& m6 i, m; qgawk 根据 field separator 将一个记录分解成栏位。field sepa-
- ]* \- W9 \+ I1 ]# v$ d9 grator 以内建变数 FS 表示。
@' i) O# @( A0 k9 r: d2 t举个例子,假如 field separator 是'oo',则下面的行:9 T( s, F& m6 O! A9 o. P
moo goo gai pan" H$ c. Y: u( d$ q% r
会被分成三个栏位:'m'、' g'、' gai pan'。 ]3 N7 M3 N: p
在 gawk 程式里,可以使用'='来改变 FS 的值。例如:- F- M5 z7 |( {- I% @5 J6 p
gawk 'BEGIN {FS=","}; {print $2}': X( P$ q1 f z2 K4 W6 f% U
输入行如下:
6 Z6 Y) ]: L: o, SJohn Q. Smith, 29 Oak St., Walamazoo, MI 42139" z/ y9 c E4 J# h- {, }
执行gawk的结果将印出字串 ' 29 Oak St.'。BEGIN 後面的 action 会在
$ M) B- }' g( [. K! Q" V, f, t第一个记录被读取之前执行一次。
- K' r0 k( L6 i+ C6 ^, L
1 Q" o% R7 ^) u( G第四章 印出
1 W, d) }/ v& v, L, H% y( T" n6 d& \在gawk程式里,actions 最常做的事就是印出(printing)。简单
! Q; }. d. O- r1 Y的印出,使用 printe叙述。复杂格式的印出,使用 printf 叙述。$ h/ A, e+ J& K
8 ^' `5 S8 x% b) |! }2 @5 j G$ E: J4.1 print叙述9 M! `4 J( g' E
print 叙述用在简单、标准的输出格式。叙述的格式如下所示:
( e9 Y- _& ~' |6 m/ @print item1, item2, ...
; K) p, u. V( U输出时,各个 item 之间会以一个空白分开,最後会换行(newline)。
0 j; \' J" F* n( O如果 'print'叙述之後没有跟著任何东西,它与'print $0'的效! u: b5 M6 S7 F3 `+ s& X. c6 o, D- Z
果一样,它会印出现在的记录(record)。要印出空白行可使用'print
( u* q& S/ _- `9 O3 r# i/ {4 n""'。 印出一段固定的文字,可用双引号将文字的两边括起来,例如. Q+ v" m- o/ r. @- p! a
'print "Hello there"'。
% Y7 C& h" P5 R7 @$ ]" z% Q这里是一个例子,它会把每个输入记录的前二个栏位印出:0 V2 ~. h% {* A6 F( M& {' j
gawk '{print $1,$2}' shipped
' }, f: L3 X5 X+ z8 C. U7 o结果如下所示:
! s" N3 h; ^2 N0 n! R6 dJan 13
( [: w& z- H M9 vFeb 15
1 w% y. h' {: dMar 15
4 J1 m- u! V5 T( x. r- qApr 31
2 s; Q( e, X, [) B/ [6 }May 16) N7 k9 l( I) E! I1 l! f$ Y) C
Jun 31
- g4 V, q$ A: `9 MJul 24, {! n U, h- q; x" w [* g
Aug 15
& H4 ~. n Z9 q% NSep 13
5 i+ s$ C4 |$ h3 X! a, iOct 29) `4 \/ i- E( ^9 m! n
Nov 20# N: W7 C! e1 y4 |' l
Dec 17
9 X& H9 O" U+ ?% h0 oJan 21
1 h w- g# N5 R, ^Feb 26
C8 ]- A- R9 L1 A0 `: _% T3 {Mar 242 b& |- d9 m- }6 U- u7 P+ A$ Y
Apr 219 e/ S4 m% b$ v! f* b7 Z
6 u7 i( G% C6 G4 z4.2 Output Separators
; [. g( x; X( k5 u* J前面我们已提过如果 print 叙述包含有多个 item,item 之间; N2 o) I! D( i; i# N2 s4 u
用逗点分开,则印出时各个item会被一个空白隔开。你能够使用任何+ @- j$ L. ?' S4 Y# w" y* G" ~
的字串作为 output field separator,可以经由内建变数 OFS 的设
1 Z" a4 |5 v- G) _! q/ m- F定来更改 output field separator。OFS 的初始值为" ",即一格的
7 q( U) }' d7 b- V% m空白。
4 N8 A& V; O% H/ W4 z整个 print 叙述的输出被称为 output record。print 叙述输
# t7 I; i6 K1 p+ z% h出 output record 之後,会接著输出一个字串,此字串称为 output
1 G! @) P% o- K) Mrecord separator。内建变数 ORS 用来指明此字串。ORS 的初始值
: a. U% w& o0 C$ F* W% n为 "\n",也就是换行。
$ g5 I2 y( L/ A6 k8 \下面这个例子会印出每个记录的第一个栏位和第二个栏位,此二; ^( H) j$ C1 ?* r ~7 A; L
个栏位之间以分号';'分开,每行输出之後会加入一个空白行。: Y! z4 ]2 x- @: ^: G
gawk 'BEGIN {OFS=";"; ORS="\n\n"} {print $1, $2}' BBS-list
) |( t; X+ k" O* D# O结果如下所示:) u! a1 Z C. B2 R2 G
aardvark;555-5553
( Y; {" J, T2 Lalpo-net;555-3412) G: v. c, R- _! J% H
barfly;555-7685
: E5 B& P" d2 ?1 J+ Pbites;555-1675
3 k2 H; c! E( w0 Kcamelot;555-0542
# r3 p: M$ U, R* N# bcore;555-2912! ?' N+ p. a3 c! A) a: e0 \
fooey;555-1234/ W9 a/ s) S* l; m/ ]. H
foot;555-6699
" }) j, Q/ p3 U& ~2 g& u* N# f7 v" S- ~macfoo;555-64804 i. G7 X, S5 M9 a$ v
sdace;555-3430
' }5 O6 N$ p3 \sabafoo;555-21274 B! G. x3 z* I/ ]
2 _) J8 h0 X6 z M' J4.3 printf叙述
" `- J5 x8 O' Aprintf 叙述会使得输出格式较容易精确地控制。printf 叙述可以
! C% C% |9 I% i指定每个 item 印出的宽度,也可以指定数字的各种型式。0 A/ V3 K8 h" {! Y% G8 B! r1 |6 g
printf 叙述的格式如下:
. t: I9 A* B* I ?' D- W+ v2 I+ T1 o; \printf format, item1, item2, ...
0 B q3 Z) L) _# I# yprint 与 printf 的差别是在於 format, printf 的引数比 print+ f" V: D K7 `5 _* o
多了字串 format。format 的型式与 ANSI C 的 printf 之格式相同。
! y$ ` m* q' v* K4 k# |6 Uprintf 并不会做自动换行的动作。内建变数 OFS 与 ORS 对 printf 叙
( V h% ^, t. w9 [述没有任何影响。
! o3 h; m1 d% _3 A9 T/ S& Y, S, Q格式的指定以字元'%'开始,後面接著格式控制字母。
, z8 `- Z3 h5 h格式控制字母如下所示:5 {+ ^* @ k: M" u* M8 Q
'c' 将数字以 ASCII 字元印出。
* {6 c3 v0 H1 L8 B( Y; J例如'printf "%C",65'会印出字元'A'。
7 S( y' t7 M7 {' J9 p'd' 印出十进位的整数。8 T! _% }+ z p2 A1 Z$ P0 I; ^
'i' 印出十进位的整数。
# Y- l4 F6 Z4 Y& [8 T'e' 将数字以科学符号的形式印出。4 w; D/ @; ~4 a/ F2 x3 g% \: ~
例如
( O: r& o" w; z% f7 L6 o+ Xprint "$4.3e",1950$ C; c0 l. E* a* |
结果会印出'1.950e+03'。/ S/ p% V0 j% L9 O$ D) t6 T
'f' 将数字以浮点的形式印出。
0 m" ~; M/ U( N1 G'g' 将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果
0 s4 F; X# w+ q8 G. O+ R* _! N大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印: Z4 Y) [/ @* G' r% {# i, s! {
出。
! w/ E6 C1 Q7 |; j6 z& t'o' 印出无号的八进位整数。
. S$ ~2 P/ N2 Y* I8 z's' 印出一个字串。
: Q( J4 ]6 B) C8 K4 m'x' 印出无号的十六进位整数。10至15以'a'至'f'表示。
3 G4 o: z8 z' }' q'X' 印出无号的十六进位整数。10至15以'A'至'F"表示。$ }2 ~( S+ f& V% U/ Q
'%' 它并不是真正的格式控制字母,'%%"将印出"%'。
3 G& I/ {9 ?) l1 I在 % 与格式控制字母之间可加入 modifier,modifier 是用来进一
! O* h+ P$ j; S1 e1 {; u& \) F% j步控制输出的格式。可能的 modifier 如下所示:. p- c" H# V0 M! P" n- n
'-' 使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在8 e; v" W w4 H6 M, s) g: }
被指定的宽度向右靠齐。例如:* h& t4 R5 m8 R" j+ Y; E7 S
printf "%-4S", "foo"
3 g$ _ B6 V2 F; U& e1 k- ?' ~会印出'foo '。" r1 S5 z, q- i2 C! p K8 s
'width' 这一个数字指示相对应的栏位印出时的宽度。例如:
1 n+ A1 U+ p, r0 z1 u- [' Bprintf "%4s","foo"
7 S" c/ P/ P- M( d会印出' foo'。
* M: @. A* n$ |# e1 H6 ?width 的值是一个最小宽度而非最大宽度。如果一个 item 的7 n3 m7 v4 I( G# Q0 O# x
值需要的宽度比 width 大,则不受 width 的影响。例如) L% E/ q" w6 L( \( M8 [& W
printf "%4s","foobar"9 ]' K; H' a3 v) h4 ?
将印出'foobar'。7 i \2 i# n; a |4 {
'.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。如
3 F F* D7 P- E: K( a/ ]果是要印出一个字串,它指定此字串最多会被印出多少个字
( P0 ?6 \2 n j, j6 h& i元。
; y2 D$ S6 W9 q$ i) [3 s+ x, j
& G0 E, `* r* c0 F1 C7 a( {! n: D第五章 patterns
5 P, }7 j2 E" M$ j g! e在 gawk 程式里面,当 pattern 符合现在的输入记录(record),其
3 G! y: x- O( M) k' J% ?, k7 k& s相对应的 action 才会被执行。5 Q4 R; N& O1 r, L! I1 t
3 `4 y0 a! u4 i+ S
5.1 Pattern的种类1 K6 Q! C# y: f E+ V) q2 E
这里对 gawk 的各种 pattern 型式作一整理:
. q9 `! Q) p' r1 [, \/regular expression/5 p! m+ O" z. r% u0 q5 _
一个 regular expression 当作一个 pattern。每当输入记录 (
, }: [# j8 x, lrecord)含有 regular expression 就视为符合。
+ k6 L* g2 _9 n5 r9 E/ t& J& Kexpression7 w: `7 u- L; F+ `7 P# u% L
一个单一的 expression。当一个值不为 0 或一个字串不是空的,+ K" X# u* c. f$ L( ?' g
则可视为符合。& l6 |3 ^/ Z- A( T% c' y: V$ V
pat1,pat2( H3 H5 N6 j& u T& F$ g
一对的 patterns 以逗号分开,指定记录的□围。( C' v1 v( o" P- U- ?
BEGIN' ]- g" x" O, ]0 e- b, ]0 d
END
; u: U" q* U- o' z. S这是特别的 pattern, gawk 在开始执行或要结束时会分别执行相
$ o8 v4 y9 Q) a" @对应於BEGIN或END的 action。) C, I r8 \* g+ M+ G
null3 B8 E3 F3 A- O3 O6 y
这是一个空的pattern,对於每个输入记录皆视为符合pattern。
0 h" e% S4 M. @/ o6 D% M
: _9 A' Z+ R) u" d7 ]+ E2 s5.2 Regular Expressions当作Patterns
$ K* R$ L% Y8 a b0 y5 j) n8 P* v一个 regular expression 可简写为 regexp,是一种描述字串的方3 e+ I7 }3 G5 c
法。一个 regular expression 以斜线('/')包围当作 gawk 的 pattern。
3 Z, l' V/ ~8 K- T5 ^! i如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,) c2 W9 ^) ~2 \0 {) i2 {2 @6 \
对於任何输入记录含有'foo'则视为符合。
) ~; f) x5 B7 `" O' l下面的例子会将含有'foo'的输入记录之第2个栏位印出。
: |9 t$ ~7 ~4 qgawk '/foo/ {print $2}' BBS-list, j* X$ Q. x- w
结果如下:. B: ]/ L: O: b0 R+ y
555-1234$ w0 l5 J$ m, Q& g- e t9 \% I" V4 |
555-66997 I! z" \+ q# {% @
555-6480
u* N: W0 L: H4 d% t' w6 x555-21271 c& O9 `- i* R% }# d
regexp 也能使用在比较的算式。/ F' W" g9 w6 |" V( R4 f
exp ~ /regexp/
% D0 [- e, \ A4 J如果 exp 符合 regexp,则结果为真(true)。8 ]6 k2 c% W4 g
exp !~ /regexp/; w7 P- g: |. e+ [
如果 exp 不符合 regexp,则结果为真。
8 O2 w) e% _; i4 J) Y% Z8 F7 e5 Z/ R9 f' S3 I; x
5.3 比较的算式当作Patterns" @8 y! d/ G* `% d8 J
比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於+ y, C O6 u6 p
、小於。下面列出一些比较的pattern:
+ Q+ [, ^, Y8 @* j- p. Z3 _ mx<y 如果 x 小於 y,则结果为真。
3 J; u5 E6 y W2 T H5 hx<=y 如果 x 小於、等於 y,则结果为真。
, K' x6 p$ d0 J: Hx>y 如果 x 大於 y,则结果为真。$ a* c3 G) a) J$ F2 m2 M/ W: r
x>=y 如果 x 大於、等於 y,则结果为真。* A) ^3 q3 I3 w/ I* _/ e
x==y 如果 x 等於 y,则结果为真。( N- J6 Y! `! l4 p
x!=y 如果 x 不等於 y,则结果为真。
- l2 I7 L0 d" ~! G) D( k1 K" V Px~y 如果 x 符合 regular expression y,则结果为真。
! X( M$ X/ p. n$ Wx!~y 如果 x 不符合 regular expression y,则结果为真。% D C" O( B4 O; q
上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,9 B4 b- n) `# m* K4 D0 W5 b
否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,
- e+ C' a2 g; K D r会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同; E% l& v3 |7 O
的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视" O# l* h" p3 n$ L; O* \; k% Q
为长的字串比短的字串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。
9 i$ D$ R0 e- {9 v6 G L; ]# @
5.4 使用布林运算的Patterns
+ R, F7 A; |$ b8 G8 I一个布林(boolean) pattern 是使用布林运算"或"('||'),"及"+ Z4 m" b! f. P( m2 G
('&&'),"反"('!')来组合其它的pattern。
5 a0 Q- R/ e* r9 J7 B例如:% u5 }+ u" i- G1 y
gawk '/2400/ && /foo/' BBS-list& s0 x8 k4 ?- E* {' ]7 z% h
gawk '/2400/ || /foo/' BBS-list4 x @, }$ O- C4 {1 g
gawk '! /foo/' BBS-list! F: u$ n' E( Q5 L
: g' Y- w2 k! P7 u, ^9 c; B+ s
第六章 算式(Expression)作为Actions的叙述
; _% Q6 b9 U$ |1 U0 m算式(Expression) 是gawk程式里面action的基本构成者。( E; C6 M; G6 U. m
; U8 n x- s- ~% b# m6 z0 O
6.1 算术运算
2 `/ O) P5 R2 l: E# Fgawk 里的算术运算如下所示:7 {1 ~ K- o' ?* e- u( Q
x+y 加0 _- q4 \2 S! J- ]7 E1 q
x-y 减
, U! A. g" k5 F, z-x 负$ t2 X# S( y) p2 |& c
+x 正。实际上没有任何影响。
6 K$ U, k. Y+ r8 v# r4 |! nx*y 乘
: |3 g$ {* p/ A5 T8 sx/y 除) x$ U h- z& v$ Y8 `( k1 a2 y+ } e
x%y 求馀数。例如 5%3=2。
: w0 Y Z4 V% M* r9 px^y
* |: J/ X, a0 n7 ~x**y x 的 y 次方。例如2^3=8。
. Q7 Z# Y9 K$ q P4 s
* c# b1 X9 x& N! h+ }6.2 比较算式与布林算式
; p- s9 k9 ?( ?: ?比较算式 (comparison expression) 用来比较字串或数字的关系 u5 m" D c% F
,运算符号与 C 语言相同。表列如下:
0 Z6 }! C" Z; |" ?4 V# n. ix<y& _! g6 w" |, m$ q0 f8 {
x<=y- U" Y# K' f# L3 j& j7 U
x>y8 s' |/ Z) I2 i5 P
x>=y
# Z$ Z$ ]5 Z; h; o9 |$ Ax==y
: J% i' d3 N2 j. T0 K9 v$ b& ?, Gx!=y
$ \- O/ u' |, g& n' x" ~% L7 Wx~y3 B" `# e# o3 f
x!~y# ? y* w0 q1 j' `* S
比较的结果为真(true)则其值是 1。否则其值是 0。4 X0 i/ ~2 N& {5 t! E
布林算式(boolean expression)有下面三种:
, q E7 {% w* vboolean1 && boolean2
% Z( o2 w( C. A9 jboolean1 || boolean2$ w8 g2 F' E: m
! boolean$ m1 @0 L e8 H, S8 l0 L) A p
/ z3 N3 S0 S' R; N2 d6.3 条件算式(Conditional Expressions)
* J; e1 v7 \! B+ K一个条件式算式是一种特别的算式,它含有3个运算元。
0 p- {& J& V" O0 r( G条件式算式与C语言的相同:# D; h8 L: R* C/ v \* ~: {
selector ? if-true-exp : if-false-exp
, L$ h# {5 W: O1 h" j它有3个子算式。第一个子算式selector 首先会被计算。如果是真,# t9 R6 Y# P; i% h! d
则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-4 W$ Y4 C. }0 x# U& r d
exp 会被计算且它的值变成整个算式的值。. c; C2 E2 W& z0 m
例如下面的例子会产生x的绝对值:& |& ~ m( l# K+ j
x>0 ? x : -x
' V9 @8 \( G' v% a$ f G9 X7 m- w3 {
K# f$ l; T' I, t2 a- k" m$ h第七章 Actions里面的控制叙述
+ e0 |7 w4 q' [在 gawk 程式里面,控制叙述诸如 if、while 等控制程式执行的流# U1 `8 i' b d- h6 o1 Q
程。在 gawk 里的控制叙述与 C 的类似。0 I" Q9 m" }4 m: S
很多的控制叙述会包括其它的叙述,被包括的叙述称为 body。假' X% i: J# N4 X- C# h' s
如 body 里面包括一个以上的叙述,必须以大括弧 { } 将这些叙述括起
8 k" e$ [0 a" u% {( K/ O来,而各个叙述之间需以换行(newline)或分号隔开。
; {# O: u4 G2 P) u/ r4 V) I! Y
5 Q/ R* s% E+ k. |) C7.1 if 叙述, n) e) |7 y, \+ d' h: A& h& E
if (condition) then-body [else else-body]
) F2 w" \0 m% c/ k& A' n2 i如果 condition 为真(true),则执行 then-body,否则执行 else-body。
- d& s( p+ @! d+ `举一个例子如下:
5 @/ [: V" g$ Z) x6 \4 K& Lif (x % 2 == 0)( c- t5 ^* M% k0 m* C* e/ F
print "x is even"
8 a. t1 W7 `* m4 B% ielse$ X! G& [4 L5 c) ?
print "x is odd", E) E1 G& d: V
& C/ G6 I9 _1 D* C2 f
7.2 while 叙述
$ k3 L; l8 m# I0 q& F8 J+ |9 Ewhile (condition); g3 I0 ]8 k" |; {1 L
body
2 ?, z) k' H6 @' Dwhile 叙述做的第一件事就是测试 condition。假如 condition 为真则- q! g) g2 H! Y: O0 _, _
执行 body 的叙述。body 的叙述执行完後,会再测试 condition,假如
/ o6 d* A+ d4 l' y, U! Y" Fcondition 为真,则 body 会再度被执行。这个过程会一直被重复直到7 V/ N$ g, N7 I5 m, p
condition 不再是真。如果 condition 第一次测试就是伪(false),则/ d' ?8 B* _0 E" v4 ?
body 从没有被执行。
( F" D0 ?# `- ^3 ?) n下面的例子会印出每个输入记录(record)的前三个栏位。
* p8 X5 \7 v3 g+ P& o( |8 ogawk '{ i=1
# u/ A% ]" X/ P! Z6 ]while (i <= 3) {
/ z) v9 d; f' n, O- M6 R9 cprint $i, M0 M$ a E1 t6 `8 e+ F+ L
i++
/ B7 [) ]1 E( H \5 p- l7 d}0 e z) E5 c! I8 d: l9 M! T; ~
}'
$ A2 D4 T$ `2 T- g
" i+ U9 C4 r6 ]7.3 do-while 叙述' D( v9 Z3 O- Y# q+ S) c' L
do
# c6 S5 D- w" A4 Ibody$ G3 V; V' y5 ~$ a$ D
while (condition)
2 q8 l& R& [& F3 x; \" ^! s这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。
" `! }: D. q$ b& Y0 I9 X9 A即使开始时 condition 是伪,body 也会被执行一次。. O7 X5 g2 r2 Q3 b! }, M) N
下面的例子会印出每个输入记录十次。0 G0 u' w: @% G$ ?
gawk '{ i= 17 M& Y' M8 Q5 \
do {9 r+ Q3 r% {# m% G* J
print $0
# K! N; U8 C; W# o0 R+ ~) B, Ui++
! w( _- k7 N8 x( u, k} while (i <= 10)* R- ?6 l4 A+ q& H
}'' X2 U! A7 m) m; H
. D9 S; Z% ^: s# E0 _7.4 for 叙述+ f/ Z# l* Y9 D0 s
for (initialization; condition; increment); r2 f+ S+ W# [7 m
body
8 l: H9 @: N$ C6 O此叙述开始时会执行initialization,然後只要 condition是真,它2 \$ V1 O p8 R% f
会重复执行body与做increment 。
9 H. J, U. P2 @, ?- Y( w下面的例子会印出每个输入记录的前三个栏位。
5 \6 T. m/ v7 l- L4 jgawk '{ for (i=1; i<=3; i++)
7 l, G. P! X3 N$ o! s+ Jprint $i- H+ T' u5 J; G
}', l1 d: O8 ~2 E* e6 D7 j
/ f9 v% f: F: v7.5 break 叙述
9 ~5 l: i- C/ L- U9 {$ Mbreak 叙述会跳出包含它的 for、while、do-while 回圈的最内层。
' k& E6 v) z1 P' W% U6 U下面的例子会找出任何整数的最小除数,它也会判断是否为质数。
g5 \: L/ G2 M0 y( kgawk '# find smallest divisor of num
' t( F' d; N ~& a2 d+ p{ num=$1. D% C; X6 _, |$ ]1 Q2 G2 x
for (div=2; div*div <=num; div++)0 G, l [$ p+ N& c7 l
if (num % div == 0), z" B) S8 I6 P0 T2 D2 J+ f
break1 I. u9 ]9 Z0 \6 D5 {' h }9 T
if (num % div == 0)
; T5 N' U; u- _9 { Jprintf "Smallest divisor of %d is %d\n", num, div& v) y0 A9 S2 I* U( t
else- I m9 f7 N+ K0 d, n1 ]
printf "%d is prime\n", num }'5 h7 B" [1 h J- |; _5 E
g% [ ~0 J) m2 w6 j+ ?2 `
7.6 continue 叙述2 Y9 u# K" o) ], {+ k$ @
continue 叙述使用於 for、while、do-while 回圈内部,它会跳7 s8 r2 J" i" X* E8 n& [9 O; b
过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。& f4 ~, v/ T/ l/ N1 n. N" ?# I
下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。% V- k8 O8 m o. O9 X
gawk 'BEGIN {
& F, q j! B! [0 E5 Q' q" Sfor (x=0; x<=20; x++) {
- a/ Y3 e1 P- Iif (x==5)
0 x# x a0 G* G2 F, Icontinue
- }8 [3 V- Q, J1 {# J% gprintf ("%d",x)
9 H% s; S. v: w% C* c}
: s5 i6 d7 G$ `* n' Gprint ""
h. B) Q" B7 t1 G7 q9 c}'
2 d0 t% k; ~+ x/ v5 j6 M3 F8 Y3 c6 c# w
' v- u, A o% i2 m! H" h8 S4 \7.7 next 叙述、next file 叙述、exit 叙述
2 Q/ k% }; | ]& U% @% n: @. w; L p5 Nnext 叙述强迫 gawk 立刻停止处理目前的记录(record)而继续下一4 w) x5 C& c$ a3 Y% H
个记录。
/ J- H4 D4 U; s7 i7 inext file 叙述类似 next。然而,它强迫 gawk 立刻停止处理目前
) e7 Y2 \' g/ k3 t1 h) `的资料档。6 i" D y, n4 j4 C9 q' d3 `
exit 叙述会使得 gawk 程式停止执行而跳出。然而,如果 END 出现
1 { |8 Q+ t$ V' o6 u6 W4 Q,它会去执行 END 的 actions。
; N5 n5 q2 N; ]
9 q+ K# X5 `- Z9 M6 u& @第八章 内建函式(Built-in Functions)
' B" w, M& \: L6 e0 C1 r内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建
" K% i/ `" E& j' A. W3 K6 i' J函式。
; ~' V3 J0 l& z. ?- U$ i N* f+ b3 W
8 g5 \/ b& d1 M7 y0 U2 M) L* N8.1 数值方面的内建函式- t: j; @+ y$ Z
int(x) 求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9)
9 `6 e& Y; z% X. j" q是 3,int(-3.9) 是 -3。, Z! x; ]) J, k9 Y; {3 \( o2 [
sqrt(x) 求出 x 正的平方根值。例 sqrt(4)=2
! g3 \- W ?6 `! e! g! Texp(x) 求出 x 的次方。例 exp(2) 即是求 e*e 。 {' x% K1 O* ]1 K4 T1 a8 w
log(x) 求出 x 的自然对数。
4 P& R4 L1 v4 ]. bsin(x) 求出 x 的 sine 值,x 是弪度量。8 l2 a5 c; x' @) D" r
cos(x) 求出 x 的 cosine 值,x 是弪度量。: f0 Q" R6 Z. X+ h) [, u' @1 Q
atan2(y,x) 求 y/x 的 arctangent 值,所求出的值其单位是弪度量。% r$ `+ ]7 Y$ E) V" |9 B( K
rand() 得出一个乱数值。此乱数值平均分布在 0 和 1 之间。这个
0 G% p/ a' v, c; S0 V S6 ~值不会是 0,也不会是 1。, J, l* Q. X5 v) d2 F: H. g5 G
每次执行 gawk,rand 开始产生数字从相同点或 seed。
, F5 m9 X" X7 t5 m( B2 }9 Qsrand(x) 设定产生乱数的开始点或 seed 为 x。如果在第二次你设4 e& o% N9 h9 f3 e' a; F
定相同的 seed 值,你将再度得到相同序列的乱数值。4 b" G- c( u/ V9 g7 ^, K/ }+ F
如果省略引数 x,例如 srand(),则现在的日期、时间会7 i% k7 i# o6 Q: a, j
被当成 seed。这个方法可使得乱数值是真正不可预测的。; r: R) G' f! r) e5 K
srand 的传回值(return value)是前次所设定的 seed 值。4 V) t0 T) M* s& Q
! y( d! i; q4 ]6 c, |2 w
8.2 字串方面的内建函式9 M0 m9 N8 `& f; B5 n9 B8 G
index(in, find)
" l% F1 N4 U7 q它会在字串 in 里面,寻找字串 find 第一次出现的地方,传回值是* V6 B4 d' b& ]/ Z O
字串 find 出现在字串 in 里面的位置。如果在字串 in 里面找不到字3 h+ I+ W% S6 O: m8 p# e$ y' Z6 U
串 find,则传回值为 0。
( J( J+ M; V2 m& q7 }$ b* \; n+ z! q例如:9 {! M$ q, Y$ h/ ]0 Y, v
print index("peanut","an")5 R' P; N- P$ `
会印出 3。
X. J4 M) G U$ {9 Flength(string)7 N8 |1 e; s @ V; `+ j
求出 string 有几个字元。" U" ~2 \- b( C
例如:% `0 V/ u- t6 m$ C1 L% a
length("abcde")& \9 y1 K+ q' D6 V0 D
是 5。 E# @1 R3 N. C' s& x
match(string,regexp)
9 e' @" Y; O9 j9 imatch 函式会在字串 string 里面,寻找符合 regexp 的最长、最靠
5 c9 O6 g* s! Q左边的子字串。传回值是 regexp 在 string 的开始位置,即 index
# ~- `: ` v) M8 L1 S# n7 o值。& t8 a8 u8 C7 k: \+ }& m. a
match 函式会设定内在变数 RSTART 等於 index,它也会设定内在变: Y+ t: `% J- }# l5 P+ S
数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为
6 J5 `# e d0 [+ b+ \5 F z0、RLENGTH 为 -1。; }# K( E5 S" L; p) A
sprintf(format,expression1,...)
' o$ Q( Q% v; S举 printf 类似,但是 sprintf 并不印出,而是传回字串。
/ ]$ y& q( a3 O' B例如:
$ K9 Z$ r W+ @; M4 y7 bsprintf("pi = %.2f (approx.)',22/7)! H2 i5 e. w8 o# W# J
传回的字串为"pi = 3.14 (approx.)"
+ H6 x8 j6 _2 i0 n( Z! Bsub(regexp, replacement,target)- h( B7 d" Z) J/ D8 ?2 q/ R t
在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方," U! [7 j& l6 P$ H
以字串 replacement 代替最左边的 regexp。
) ~& f; B0 p6 T. `例如:
, x1 R/ V% s5 T2 Bstr = "water, water, everywhere"
\& d- k, O6 i) \9 {3 P3 Tsub(/at/, "ith",str); O* O/ B4 i6 N
结果字串str会变成
7 i6 h6 ^/ r7 Z"wither, water, everywhere"0 }; [$ S) s. @) R3 r& \
gsub(regexp, replacement, target)
2 k. V* o2 ~7 bgsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的
- R, x- X# \. ^所有地方,以字串 replacement 代替所有的 regexp。! h& z! f) Z, @" d3 b5 d
例如: P, N9 O4 c! b' C9 B" K
str="water, water, everywhere"
# s ~% ^2 f, g* N: b, Dgsub(/at/, "ith",str)9 }0 v( h$ R$ A) V: x1 m
结果字串str会变成
' l: R8 O( O/ X1 f0 Y P: c/ n/ r'wither, wither, everywhere"# y0 y# e* D1 x
substr(string, start, length)! B, d8 ~/ H m! C# l0 u
传回字串 string 的子字串,这个子字串的长度为 length 个字元,
' @. |$ u, [' M6 v0 m从第 start 个位置开始。
' z, f8 Z2 }( o" p- g: @例如:
9 z; i7 h6 U; @6 @% [substr("washington",5,3)9 R/ ]$ Y* h, E
传回值为"ing"2 w& [* X- R2 y8 ^6 d! L
如果 length 没有出现,则传回的子字串是从第 start 个位置开始
1 X5 ]4 G2 u( R4 L至结束。
. ]( p) Y' C) @4 u例如:
$ C) I" @0 N/ P7 Jsubstr("washington",5)1 ?1 D- E4 O+ C5 h x' z3 `0 K. \, |
传回值为"ington" j" a" T6 O/ h3 m
tolower(string)
/ U! T/ e& O9 x. _将字串string的大写字母改为小写字母。
+ B* P$ _/ W8 J/ F$ y& F, h5 E) {4 V例如:
. _6 F1 d/ d+ _$ V/ [tolower("MiXeD cAsE 123")5 j: ^. g. {8 `6 Z8 ^
传回值为"mixed case 123"
; C' l5 Q) j4 y$ W+ Htoupper(string)
/ r. N" ~" ^0 a/ R& A将字串string的小写字母改为大写字母。* W! G5 @# s4 w( k
例如:& q; T. f0 ^3 M' S2 M
toupper("MiXeD cAsE 123")' k# X+ e; k3 g/ }5 F
传回值为"MIXED CASE 123", F' x; J" `% u E% Q b6 u
% R4 K1 B! |0 X7 L* T
8.3 输入输出的内建函式/ n& o: z& |: Y( M! H; H
close(filename)
$ B$ `. o: T) v. I将输入或输出的档案 filename 关闭。8 `% F1 i+ B' B) M' j* X8 ?
system(command)9 ~/ C! G* e) A$ f8 `' p$ b+ H. x
此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk. y9 g% w* S/ @2 f0 h
程式。
- j! t& F) U' J( ^9 q例如:$ _8 Q3 a$ g, j z& J1 n
BEGIN {system("ls")}! f+ y" i: c9 P
% w3 Y& U$ m6 y4 a1 O5 d
第九章 使用者定义的函式(User-defined Functions)- d( r3 c! e( m5 _& K7 H3 i
复杂的 gawk 程式常常可以使用自己定义的函式来简化。呼叫使用
2 X2 `9 ^: m3 n1 L9 W4 |3 e" V者定义的函式与呼叫内建函式的方法一样。* K4 I; S# C+ U2 d0 [% h2 U N. D
4 v( h- w) S; M9.1 函式定义的格式1 q3 e5 e5 L- H+ U7 a
函式的定义可以放在 gawk 程式的任何地方。# S* G r; b1 N5 ?/ m A! a
一个使用者定义的函式其格式如下:
" ^& j: Z0 q+ o( ^+ Z0 `; K O/ [function name (parameter-list) {, S! \5 \8 y# t" N* Y5 w0 p; E
body-of-function& b9 O2 V' d( T4 R: i. P
}
+ q* E, t, s4 |$ ?: n* R0 iname 是所定义的函式之名称。一个正确的函式名称可包括一序列的字7 o" ^4 v5 ^. Z
母、数字、下标线 (underscores),但是不可用数字做开头。
5 c9 i0 E! h$ G; O8 P- Kparameter-list 是列出函式的全部引数(argument),各个引数之
6 n5 h0 u" y& C* c间以逗点隔开。& ~9 ^& w( t& P- Z5 \7 H
body-of-function 包含 gawk 的叙述 (statement)。它是函式定义
: X4 B; G) B1 T. Q/ z里最重要的部份,它决定函式实际要做何种事。
' x% ?5 v# Q% s- K8 @* y9 m" Q
5 e; W' ?& z" H- W9.2 函式定义的例子6 Y6 A$ m5 d6 G, G8 `1 e4 M% D
下面这个例子,会将每个记录的第一个栏位之值的平方与第二个
- s+ W1 o- [: e栏位之值的平方加起来。% M4 E" Q B' _8 X$ }/ d
{print "sum =",SquareSum($1,$2)}) w4 P9 [" |$ i
function SquareSum(x,y) {
1 F( C" Q% ^: c( I8 v4 j" n9 isum=x*x+y*y0 a1 n& |0 x: b
return sum
9 ]' A5 X6 k" N}
6 J0 n2 ]* w" q- B2 f9 H# F$ a3 j" |" T/ l8 h
第十章 □例
* W% P2 [/ U% ]( K9 b这里将列出 gawk 程式的一些例子。
3 ?3 U' V! f% \5 O/ f& m5 hgawk '{if (NF > max) max = NF}& V/ q+ G9 e+ n4 X( K
END {print max}'7 c3 t/ k8 e; [" I
此程式会印出所有输入行之中,栏位的最大个数。
) m& W2 H' ^: K8 m3 K$ I" O6 }gawk 'length($0) > 80'
, D1 ~2 e+ Q4 M. X此程式会印出一行超过 80 个字元的每一行。此处只有 pattern 被2 O1 g, z) h9 f$ H7 \; q( ]
列出,action 是采用内定的 print。
+ H8 u. P1 r' r/ Y6 i: _, D! vgawk 'NF > 0'
- f; q# U, M; M% _; X% Q对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简5 E; }- T: _7 e/ L% s
单的方法,将一个档案里的所有空白行删除。
; w! Q1 W# ]4 ^3 Wgawk '{if (NF > 0) print}'
& p# G( F; J8 V. G对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简 E* n- p7 e9 E' B6 f
单的方法,将一个档案里的所有空白行删除。
4 S7 y3 T( z/ e# q- Q3 rgawk 'BEGIN {for (i = 1; i <= 7; i++)& ?7 |7 x4 f; f, I5 @3 s
print int(101 * rand())}'
7 g' }# O$ u# [. F此程式会印出□围是 0 到 100 之间的 7 个乱数值。% R5 A, ~! @: U* K B) V
ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
% s9 Q: i7 ^1 u/ |此程式会印出所有指定的档案之bytes数目的总和。
( n( S/ h: ]* O7 M, G) A$ \! l5 [expand file | gawk '{if (x < length()) x = length()}2 v$ K) A! M+ ?8 B0 \: T
END {print "maximum line length is " x}'7 k# S' n7 I7 u+ |
此程式会将指定档案里最长一行的长度印出。expand 会将 tab 改: I) ~( A x: }" ^
成 space,所以是用实际的右边界来做长度的比较。
. W, u5 c7 n! Z+ ]0 Jgawk 'BEGIN {FS = ":"}
" U) |/ S: T- D* _$ R+ B{print $1 | "sort"}' /etc/passwd
1 C9 S+ Q5 D; D g+ ?此程式会将所有使用者的login名称,依照字母的顺序印出。
f8 T2 I: r, }; h- T; h6 P' v8 g9 ^gawk '{nlines++}
9 ?" U* r4 l" r' r" z4 _8 s1 zEND {print nlines}'
+ j& D1 s( n) N5 G5 w此程式会将一个档案的总行数印出。, }( ]! }( c3 d- A
gawk 'END {print NR}'
c) B. i; ^- a9 F2 ~% ?此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk2 [/ W0 x/ N& p2 K: R: b
来做。! \: `8 s6 ~$ w' t# ^& F
gawk '{print NR,$0}'
6 U* W& F4 i Q% C此程式印出档案的内容时,会在每行的最前面印出行号,它的功
& f& }+ _3 j3 l5 L8 h能与 'cat -n' 类似。6 L" j+ x" h5 N6 _
5 b& J8 o) N0 v% i. J* K2 X
第十一章 结论
. J4 X2 A" k: vgawk 对於资料的处理具有很强的功能。它能够以很短的程式完成
2 V3 O/ ]1 h; c想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件
! {# e: q2 N3 `% A4 Q' d工作,以 gawk 程式来写会比用其它程式语言来写短很多。
r- }0 i+ P3 ?& K, D! V5 fgawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使
4 ~& y1 F! Y" ~% \用。 |
|