TA的每日心情 | 奋斗 2019-2-12 09:32 |
|---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到 累计签到:1 天 连续签到:1 天
|
|
马上加入,结交更多好友,共享更多资料,让你轻松玩转电力研学社区!
您需要 登录 才可以下载或查看,没有账号?立即加入
×
GAWK
# I. s1 e; ^. L% V. Y7 {, v第一章 前言9 Y0 J2 f8 ?& j- [; @; M
第二章 简介! G( ^! D+ E }5 j" {
第三章 读取输入档案
1 c7 y8 y- R7 j# g- z: w! Y第四章 印出
1 d O, i. {7 b2 w5 l第五章 Patterns" U2 c7 v4 p' y
第六章 算式(Expression)作为Actions的叙述" z: k+ z9 l! E/ ~
第七章 Actions里面的控制叙述1 x6 R% g% s. n2 y" {
第八章 内建函式(Built-in Functions)
$ Q! Y, g; z, A$ x6 Z- o8 i! \第九章 使用者定义的函式
; J" Y4 s: }0 x' A& J* S4 Q第十章 □例
; k; F* h8 ^% \$ r2 ?第十一章 结论/ ^' X$ m1 r. K/ f- a
( a! q8 r7 V" e7 E$ w: l=======================================# C) Q5 N7 o' [2 w- t( J! E8 j
第一章 前言# @3 \. @7 T; \% B& ]* H% q
awk 是一个程式语言,对於资料的处理具有很强的功能。对於文3 H2 @. Z+ R' t/ y. Q
字档里的资料做修改、比对、抽取等的处理,awk 能够以很短的程式" s5 f0 o3 m' k- v2 {3 a
轻易地完成。如果使用 C 或 Pascal 等语言写程式完成上述的动作,: F: V. E* F3 R* r4 h, C. s; a
会不方便且很花费时间,所写的程式也会很大。
, ~* v, F! o. p. X3 p8 Zawk 能够依照使用者的定义格式来分解输入资料,也可依照使用
/ Z& o4 k+ M$ t) L" f7 }- G) B7 u者定义的格式来印出资料。. d9 D9 ^% C: |0 R5 M6 h
awk 名称的由来是由它的原始设计者的姓氏之第一个字母而命名
' D( g' F/ l! d; ^3 m; I* D# Z2 u; ]:Alfred V. Aho, Peter J. Weinberger, Brian W. Kernighan。
0 E/ Z+ C" ]; O$ P# @awk最初在1977年完成。一个新版本的awk在1985年被发表,它的功能
3 A2 u4 O! U0 E) N9 }2 D- V( `: S比旧版本增强不少。
$ |* D- j, K' O9 H/ W% P2 Ugawk 是GNU所做的 awk,gawk 最初在1986年完成,之後不断地
2 T( n' x* y2 A2 s/ P# c被改进、更新。gawk 包含 awk 的所有功能。
+ S6 K. X$ C) m$ w' n9 r往後的 gawk 将以下面的2个输入档案来做例子说明。: X8 F: K: Z- K# x1 K
档案'BBS-list':* X" G4 C2 ~- W( q
aardvark 555-5553 1200/300 B
! T5 q' Q% v `) G {alpo-net 555-3412 2400/1200/300 A7 k8 `, @( y' {4 A- m/ {% H z
barfly 555-7685 1200/300 A
: B7 y3 l( C' h, |- P3 ~7 Dbites 555-1675 2400/1200/300 A
! {& p6 i1 j t& Xcamelot 555-0542 300 C* `5 ?% E a! L9 S7 D
core 555-2912 1200/300 C
0 |3 Q- K+ f/ C) Tfooey 555-1234 2400/1200/300 B1 N# T2 k7 s- o( f4 X. n
foot 555-6699 1200/300 B& I0 B" e5 M( C. M* j& R
macfoo 555-6480 1200/300 A' d4 @/ r" t, N* T6 f2 ]+ {' p
sdace 555-3430 2400/1200/300 A
. X" L% Z; X* L2 `# ~0 z, a: Msabafoo 555-2127 1200/300 C
: m# B/ ]+ R1 T5 w, Z. {; U档案'shipped': G+ z% ?& U7 r2 [" M6 E
Jan 13 25 15 115
- a/ K# P9 C0 p, C3 r% R4 U! y' AFeb 15 32 24 226. `5 V1 e4 [& z S. B
Mar 15 24 34 228
' U2 w7 A1 e4 D' o8 h) QApr 31 52 63 420/ i# f3 C! l8 u3 t
May 16 34 29 208
( [5 R# X* a% B$ |7 f P( f1 bJun 31 42 75 492
0 V% h4 M- I: vJul 24 34 67 4368 K; V* \, L" a# j% h+ n1 s
Aug 15 34 47 316
1 [1 } O* y* HSep 13 55 37 2775 P1 Y9 q1 t$ T* U8 o
Oct 29 54 68 525
% z. n# g5 K c+ y4 y* t# ^Nov 20 87 82 5777 G# |' ?& c; W# x
Dec 17 35 61 4012 O! ]* e9 n: X/ `
Jan 21 36 64 620
7 C+ h1 d+ o6 OFeb 26 58 80 652
5 n I8 \: t N9 R: tMar 24 75 70 495/ a/ J7 |0 y/ M
Apr 21 70 74 514# a$ C. P# F/ z0 ^! s' i. Z; n. Q6 {
6 m8 ~- ~& t1 y& q1 d第二章 简介
6 @1 H' S: z3 }% T0 igawk 的主要功能是针对档案的每一行(line)搜寻指定的 patterns
6 {$ k7 ]7 g7 A( v: w- R7 e3 c; F。当一行里有符合指定的 patterns,gawk 就会在此一行执行被指定3 c: G5 u: T+ \
的 actions。 gawk 依此方式处理输入档案的每一行直到输入档案结
. x4 e4 O3 O7 K8 N W, }5 Q束。
; b: M l' [3 @2 e8 Tgawk 程式是由很多的 pattern 与 action 所组成,action 写在
( G" Q! j; d0 K" [大括号 { } 里面,一个pattern後面就跟著一个action。整个 gawk 程
$ b8 J+ U8 L/ ]式会像下面的样子:
+ a3 t- h. c) r, K$ `4 X% z4 E [, Bpattern {action}4 m1 A% t1 ~0 v s: n' m" r
pattern {action}, I/ A0 ^1 R6 m
在 gawk 程式里面的规则,pattern 或 action 能够被省略,但: n) g! o% [3 D$ I
是两个不能同时被省略。如果 pattern 被省略,对於输入档里面的
8 M! x9 }/ o. U9 {7 s每一行,action 都会被执行。如果 action 被省略,内定的 action
" M9 Z! w' H2 c8 P7 |% A则会印出所有符合 pattern 的输入行。4 w3 p% k3 M( N* k& c- ~4 W
. F+ `4 N# c- }1 _
2.1 如何执行gawk程式
5 O* Q, F0 o8 b8 Z- J* g3 p基本上,有2个方法可以执行gawk程式。) _& ~- B* v8 ?7 P4 ^: _
□如果 gawk 程式很短,则 gawk 可以直接写在 command line,如下所示:4 D1 x. d2 F+ }, J% j- b' F
gawk 'program' input-file1 input-file2 ...& H" R$ Y3 A j, f- B& D
其中 program 包括一些 pattern 和 action。' o5 A4 G* K1 z$ ]" Z
□如果 gawk 程式较长,较为方便的做法是将 gawk 程式存在一个档案,2 C9 d! [3 ~! L- m
即 patterns 与 actions 写在档名为 program-file 的档案里面,执行9 w( J7 r: V( P- y" l# R) Y
gawk 的格式如下所示: l& M/ ~3 S/ C
gawk -f program-file input-file1 input-file2 ...- c. R( A3 d- n- @
gawk 程式的档案不止一个时,执行gawk 的格式如下所示:
+ t" U' B2 ?8 fgawk -f program-file1 -f program-file2 ... input-file1% i, a# d. }) o0 Q
input-file2 ...
$ I- W5 \# k) J; ~, d: e! W- s* |4 u8 q) P! J" T) S: y# c' F9 X
2.2 一个简单的例子+ k' m/ i+ f9 c1 r# x8 x
现在我们举一个简单的例子,因为 gawk 程式很短,所以将 gawk 程
2 y$ G& w* P" z% o式直接写在 command line。
# l0 p5 f$ Q$ ^& m8 s Tgawk '/foo/ {print $0}' BBS-list5 Z! z5 l3 U- n: @
实际的 gawk 程式为 /foo/ {print $0}。/foo/ 为 pattern,意思为搜
, @9 Z/ |; X9 G0 f) R! f( v5 k( K寻输入档里的每一行是否含有子字串 'foo',如果含有 'foo' 则执行 action。
; o8 {/ {1 f/ v0 |8 ] Q6 Raction 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。
: y( L+ J* F+ g# J执行完上述指令後,会印出下面的结果:
* G/ H: F* G$ s% E. {9 _2 M5 Qfooey 555-1234 2400/1200/300 B
; Q. `4 i6 |1 P* k/ Xfoot 555-6699 1200/300 B$ r0 @* T. C8 |$ v
macfoo 555-6480 1200/300 A C& [) [ F9 w/ i$ l
sabafoo 555-2127 1200/300 C
7 W+ X1 h# O8 {1 @ ^5 |
6 y5 g U* N6 b: s% m' e2.3 一个较复杂的例子+ i" N0 U9 m* \# A" ]) s
gawk '$1 == "Feb" {sum=$2+$3} END {print sum}' shipped
& j- b* k2 w% \" S; x" P: r' X5 _现在这个例子会将输入档 'shipped' 的第一个栏位与 "Feb" 做比较
J( v8 F2 ]$ N- W2 z: P% l,如果相等,则其对应的第2栏位与第3栏位的值会被加到变数 sum。
$ C! x$ v+ t7 a1 [6 U' K- U对於输入档的每一行重复上述的动作,直到输入档的每一行都被处理& ?2 w+ L1 d$ u+ L% R2 C0 J, D
过为止。最後将 sum 的值印出。END {print sum} 的意思为在所有的输. Y4 o4 F4 P5 F q/ k) M1 I
入读完之後,执行一次 print sum 的动作,也就是把 sum 的值印出。# h% e6 y& w6 K, d& Y
下面是执行的结果:
2 p9 {5 r# b% ^; S* ~84; u0 a k5 r" X ?2 b+ M @
7 B! W: y, I. y5 H$ s2 }
第三章 读取输入档案
* i) p, ~( C; ]5 {# ]5 ogawk的输入可以从标准输入或指定的档案里读取。输入的读取单4 T# n# Y: i2 x2 L+ ]# a
位被称为”记录”(records),gawk 在做处理时,是一个记录一个记
) V/ r6 H8 K% z" k: ^ c; e录地处理。每个记录的内定值是一行(line),一个记录又被分为多个
& l( ^' X$ Q* Q1 ~. u栏位(fields)。8 v' q& Y7 K7 {2 ?
d' E U" |3 A( I& } _9 N
3.1 如何将输入分解成记录(records)
, ?0 n/ ?/ s# Xgawk 语言会把输入分解成记录(record)。记录与记录之间是以
' S. X" Y3 n: I! B/ Vrecord separator 隔开,record separator 的内定值是表示新一行的3 S I; w t0 l4 A g, `
字元(newline character),因此内定的 record separator 使得文字4 m7 g/ V: i' R
的每一行是一个记录。
6 T, `/ m: }2 P4 j7 Trecord separator 随著内建变数 RS 的改变而改变。RS 是一个字串,, m$ i' C) t3 `
它的内定值是"\n"。仅有 RS 的第一个字元是有效的,它被当作 record
9 G$ e1 r4 t; k* U: k1 Vseparator,而 RS 的其它字元会被忽略。
2 Z7 N6 j; B/ {) @, ?内建变数 FNR 会储存目前的输入档案已经被读取的记录之个数。内4 Z% u# _ Q% l' z8 Y
建变数 NR 会储存目前为止所有的输入档案已经被读取的记录之个数。: Y- l; H( [6 _' p5 I9 g" X
7 G$ m. \1 @1 h# R+ M6 t' G3.2 栏位(field). N/ y: S! v- \/ o9 T+ C" F6 A
gawk 会自动将每个记录分解成多个栏位 (field)。类似於字在一
* ?$ c( C1 W; a& A7 a* { I行里面,gawk 的内定动作会认为栏位之间是以 whitespace 分开。在7 G* N' t0 Y" n
gawk 里,whitespace 的意思是一个或多个空白或 tabs。9 z6 R: @1 f( l1 W5 q
在 gawk 程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位! K% g3 Y& l6 n& _5 e3 `" x
,依此类推。举个例子,假设输入的一行如下所示:; j3 ~4 @7 `, i# b7 q: q/ M
This seems like a pretty nice example.
1 h( e2 O) |, c0 @; q/ n第一个栏位或 $1 是'This',第二个栏位或 $2 是 'seems',依此类推。" ^; P# u9 Y. |8 z+ `" p
有个地方值得特别注意,第七个栏位或 $7 是'example.'而非'example'。 `3 u& f, z, R7 s5 U
不论有多少栏位,$NF 可用来表示一个记录的最後一个栏位。以& M% ~5 S8 p3 h. `. A* g1 p
上面的例子为例,$NF 与 $7 相同,也就是'example.'。
i+ O* S ~: e, u6 h2 INF 是一个内建变数,它的值表示目前这个记录之栏位的个数。
0 m6 ]2 g7 x% F$0,看起来好像是第零个栏位,它是一个特例,它表示整个记录。
: \( Z7 G* l1 k; t- z$ x8 ~% V3 h下面是一个较复杂的例子:1 A) E$ ~# F. k/ F
gawk '$1~/foo/ {print $0}' BBS-list3 |8 S \9 E4 g2 [! @
结果如下:) u% g8 s" \$ _$ ~) _, i2 |! [7 y
fooey 555-1234 2400/1200/300 B5 a; R3 p8 h. t+ `' d* Y: ]& L
foot 555-6699 1200/300 B% _! G' M) h, `# Y9 V) F( f6 F
macfoo 555-6480 1200/300 A
2 e% Y( P: O+ J8 f3 X9 n. K4 psabafoo 555-2127 1200/300 C
5 J- n! J% u+ b' D: B/ y- {这个例子是把输入档'BBS-list'的每个记录的第一个栏位作检查,如. \1 K9 k: n( V8 a
果它含有子字串'foo',则这一个记录会被印出。
% T4 D/ C# p. R N& K. M) e+ x+ {4 Z, ~! `8 R& S
3.3 如何将记录分解成栏位9 s8 t' C' Z; c3 ~
gawk 根据 field separator 将一个记录分解成栏位。field sepa-
7 ~7 W1 E& n* t7 O1 Orator 以内建变数 FS 表示。
5 V O' D- y# d# r8 v8 E& _& \举个例子,假如 field separator 是'oo',则下面的行:
( J% B1 [$ e2 s! j7 bmoo goo gai pan
# q6 e# `6 W8 k% N会被分成三个栏位:'m'、' g'、' gai pan'。* ]: h7 L V N4 [# I1 v" S
在 gawk 程式里,可以使用'='来改变 FS 的值。例如:
0 A& Z: n4 D3 h' V7 Bgawk 'BEGIN {FS=","}; {print $2}'4 S: k; S; {) ~% }
输入行如下:
! ^# L3 h' s/ Y2 P) wJohn Q. Smith, 29 Oak St., Walamazoo, MI 42139
9 G2 ~1 k3 N6 v4 p. o7 I执行gawk的结果将印出字串 ' 29 Oak St.'。BEGIN 後面的 action 会在
$ j4 Q/ U+ S4 m' b" k第一个记录被读取之前执行一次。
p! |( V/ ] x0 a
B' {" W Z4 Y第四章 印出! A, O" a) Z, x
在gawk程式里,actions 最常做的事就是印出(printing)。简单, z# }0 u3 L" J' A
的印出,使用 printe叙述。复杂格式的印出,使用 printf 叙述。+ f/ v5 P( o! R
: N; j- B* V7 l" ^0 V2 @0 Y2 X
4.1 print叙述) Q, Y: }# j9 ?: w8 O
print 叙述用在简单、标准的输出格式。叙述的格式如下所示:
& ?5 x! X+ f, {print item1, item2, ...1 p: U: l1 l5 Q1 P. F
输出时,各个 item 之间会以一个空白分开,最後会换行(newline)。
" r9 B! L) p. s( Y* _2 b如果 'print'叙述之後没有跟著任何东西,它与'print $0'的效
, W3 n+ Z6 L; v5 A/ N% q1 f, q果一样,它会印出现在的记录(record)。要印出空白行可使用'print
4 k. C- i: B" o# y" z% u""'。 印出一段固定的文字,可用双引号将文字的两边括起来,例如# [& {7 }2 H. e: J& q
'print "Hello there"'。( R9 d% `+ N' M1 k
这里是一个例子,它会把每个输入记录的前二个栏位印出:
8 C, W1 J! U! o( ogawk '{print $1,$2}' shipped
0 h$ K$ @0 N3 r1 y结果如下所示:- f! P& a: a' C! c6 c. Q7 G% P
Jan 13$ W% A4 u; L: j7 C; v/ X
Feb 15
5 ?0 C- `5 i/ |- QMar 15
4 G' ?9 p% O9 w: G( SApr 31
# p% O0 f" G; P& V. m8 GMay 16- O4 D, a$ G" r7 T2 Y: m8 ?4 S0 q
Jun 31
$ s! I% {5 M+ W1 _' g% Z8 |Jul 24
- X' w0 I" [% @' bAug 15
7 x: h1 l7 b% D, \6 t- E; ?% ^Sep 13
j4 o' ^ d+ q- ] R+ v% q" e5 mOct 290 G4 X$ C9 l9 z
Nov 20: [) U& A: N/ |' a! t
Dec 179 o+ L/ K" E U% F
Jan 21
1 v6 L& p7 S! YFeb 26: b. X7 Z6 M# n, N, |
Mar 24
" o$ B% b5 ?9 A9 B- y" AApr 21, s6 S( W) \$ _7 N; i& q2 h
$ p% |3 x' a, \, W' S% a4.2 Output Separators( s9 F" V& t. x/ G, y u% O
前面我们已提过如果 print 叙述包含有多个 item,item 之间
0 V9 v4 |' P7 Q+ a7 W用逗点分开,则印出时各个item会被一个空白隔开。你能够使用任何( p% K: P0 K# J. P; I' x# q
的字串作为 output field separator,可以经由内建变数 OFS 的设: }1 d) C& ` ^% Z; D7 Y
定来更改 output field separator。OFS 的初始值为" ",即一格的
) h% w1 U& q' l2 e空白。
5 C. e& N& |7 u( Z) X$ P9 U1 V' r/ R整个 print 叙述的输出被称为 output record。print 叙述输
' u9 X" o! b- q/ G( V- }2 w& q出 output record 之後,会接著输出一个字串,此字串称为 output! e. P% k( d9 y6 r
record separator。内建变数 ORS 用来指明此字串。ORS 的初始值
0 h, X' I* |1 `为 "\n",也就是换行。; e0 R( N. f. W1 @% e( ~! u, Y
下面这个例子会印出每个记录的第一个栏位和第二个栏位,此二
+ q5 F6 i2 h7 Z个栏位之间以分号';'分开,每行输出之後会加入一个空白行。. d3 R# @* C4 `* }7 X4 y6 S
gawk 'BEGIN {OFS=";"; ORS="\n\n"} {print $1, $2}' BBS-list
, B/ h* s$ X" G4 q. ]& _结果如下所示:9 U/ Z- d8 U5 e- A8 r+ T# e5 z
aardvark;555-55539 d0 D: G3 c: Y$ k$ ~8 X9 [
alpo-net;555-3412
/ d6 c; [3 t* z `" Kbarfly;555-7685
$ z+ R0 I; S5 T0 y" xbites;555-1675
" U- u9 }+ N4 n" g, Ccamelot;555-05426 j" I% f, c5 a5 V+ E- ^( b2 j
core;555-2912
- ] l6 C7 o0 e, |fooey;555-1234
- }; z1 G$ e @3 K3 l! z8 wfoot;555-6699
v, y l* {& s, q0 V3 Imacfoo;555-6480
3 ?. I" ^) f# T8 I. psdace;555-3430
, Y* A ~# g1 K6 }sabafoo;555-2127# g8 S _' S9 `0 G+ t6 o
7 J! n2 B5 w6 Z1 o e* A4.3 printf叙述
2 l& x6 T3 |. u# J" M2 hprintf 叙述会使得输出格式较容易精确地控制。printf 叙述可以3 [ U4 ~) L0 ~3 k p
指定每个 item 印出的宽度,也可以指定数字的各种型式。, S3 J1 \5 }2 W0 K8 Q4 E2 g4 b) n, X, D
printf 叙述的格式如下:
: U. i" n- t7 T/ P, v0 hprintf format, item1, item2, ...6 m4 m& z" T& n3 l8 z) m. X- T
print 与 printf 的差别是在於 format, printf 的引数比 print
Y) [' ?3 @% A u/ v( j4 g- |多了字串 format。format 的型式与 ANSI C 的 printf 之格式相同。* F; k! j8 ]( D+ g {! p% F0 Q" Y
printf 并不会做自动换行的动作。内建变数 OFS 与 ORS 对 printf 叙" l. g6 ^: j3 Q! {+ V' w
述没有任何影响。5 u- n! h# A8 _" |* `
格式的指定以字元'%'开始,後面接著格式控制字母。
: ]8 s& I; d3 ?' H格式控制字母如下所示:- u) y0 a0 J/ z7 e
'c' 将数字以 ASCII 字元印出。
% n+ ]* W1 O' p7 C: R% N# W例如'printf "%C",65'会印出字元'A'。
4 H* N9 K; r/ n+ F% c$ D'd' 印出十进位的整数。7 J* U: E3 ~3 z' e5 T: v% S
'i' 印出十进位的整数。
4 B+ x) p9 u* E/ Y, h'e' 将数字以科学符号的形式印出。
& N6 e% e: c# G( A& d0 P" p+ x例如' O' j1 ?( l3 a# o+ G
print "$4.3e",1950, j! L$ ]) f6 U6 j9 O, L o
结果会印出'1.950e+03'。
: v2 V7 ], |" ~'f' 将数字以浮点的形式印出。
$ c; n/ I2 h3 }1 p& |2 m( u'g' 将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果2 ?( G% x9 G) r: S0 X6 _! F& ^+ s
大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印0 G) w5 ^1 {* Y2 n ^6 X7 ]8 R1 H' g
出。
2 T- {( h" ]6 L'o' 印出无号的八进位整数。5 T+ K' a# \+ a6 f" v
's' 印出一个字串。
6 K8 v9 @/ s- v+ t'x' 印出无号的十六进位整数。10至15以'a'至'f'表示。' Q" ^! X2 {9 H" z' F5 B
'X' 印出无号的十六进位整数。10至15以'A'至'F"表示。4 X5 P" R, }0 ?3 ?& ?* i8 K6 T& [
'%' 它并不是真正的格式控制字母,'%%"将印出"%'。; m2 _; X x. A* T4 |: H E
在 % 与格式控制字母之间可加入 modifier,modifier 是用来进一6 _* M4 H ]( t4 e
步控制输出的格式。可能的 modifier 如下所示:7 i# I- W/ Y: M8 v, l
'-' 使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在
0 `( L3 I5 ?6 h) _+ C被指定的宽度向右靠齐。例如:: {% d! N# |- q" _1 }, C" S
printf "%-4S", "foo"
' ^; }# P+ {; b2 f( S0 _6 d会印出'foo '。9 K2 |8 ^3 L# U3 E
'width' 这一个数字指示相对应的栏位印出时的宽度。例如:5 H. ~: w$ N" u
printf "%4s","foo"1 S+ q9 R7 {& `! w, m
会印出' foo'。
' F$ D/ I9 T) Z1 w8 E8 ]width 的值是一个最小宽度而非最大宽度。如果一个 item 的0 q0 }5 F5 i6 s2 s/ G* W* O
值需要的宽度比 width 大,则不受 width 的影响。例如
( {6 H: S- b# U4 |printf "%4s","foobar"
+ Q7 ^7 R- }( @; b; h3 ~7 Y6 }将印出'foobar'。
u- X! |' O( r* P'.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。如
! J' V0 @3 R6 A- l果是要印出一个字串,它指定此字串最多会被印出多少个字
( p% A, P# x+ y0 E6 m( \1 W5 s$ L元。
4 _7 s- S% ]4 S% d
& w3 R7 b p" ]9 s: y: i) z第五章 patterns1 Z w0 W3 M( z2 k& q; V. d4 T
在 gawk 程式里面,当 pattern 符合现在的输入记录(record),其+ O4 m: G- o' }1 R& O, m2 E
相对应的 action 才会被执行。3 y: j6 K; G: a9 p, {1 {
* ?) S# z" L5 S0 y, {& V5 H5.1 Pattern的种类! W& ?1 N: a6 s. y2 v
这里对 gawk 的各种 pattern 型式作一整理:2 B6 g: ^# [6 W9 L: [
/regular expression/% c' C0 I2 I. u# W
一个 regular expression 当作一个 pattern。每当输入记录 (3 U1 ]" m, X+ @; X7 w( B
record)含有 regular expression 就视为符合。6 n @2 ~, ]( T
expression8 N. I( s7 s4 X. X' b
一个单一的 expression。当一个值不为 0 或一个字串不是空的,
& N- ~5 e! o# D# C1 |则可视为符合。
: @$ ?: K. t; H& s/ |pat1,pat2
$ ?0 T+ d( ?- t: f0 p一对的 patterns 以逗号分开,指定记录的□围。
- n/ y- G- t k5 Z3 A+ C" ]BEGIN
! v' {% D8 O; B1 O# JEND
7 `; P: Q; {/ t这是特别的 pattern, gawk 在开始执行或要结束时会分别执行相
( S1 N) v- K7 s7 e7 b1 g对应於BEGIN或END的 action。
0 q8 l2 K. [! ~& }null' B; m i7 |6 K/ C( s7 u" \5 Z
这是一个空的pattern,对於每个输入记录皆视为符合pattern。! f" A/ P" N6 T% Y3 ^3 S" X
: b" M/ U9 H& M3 i
5.2 Regular Expressions当作Patterns
/ Z) k9 ?( A( ~8 f, \& s/ W一个 regular expression 可简写为 regexp,是一种描述字串的方
/ R J8 V) y5 T: A) ]法。一个 regular expression 以斜线('/')包围当作 gawk 的 pattern。7 E0 K) L6 r9 s5 @( P5 Z
如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,
$ R2 i, t* h- |, G对於任何输入记录含有'foo'则视为符合。+ j7 V% l/ ?1 Z" `! ~' S$ h/ z+ t
下面的例子会将含有'foo'的输入记录之第2个栏位印出。* T3 M5 \0 u: ]
gawk '/foo/ {print $2}' BBS-list
/ [! d* j" R0 h4 c/ `3 @/ w结果如下:
v. u! R1 h- u3 V5 \. I& H# I# @555-1234/ y7 Z" p( l1 g7 k) Y! v
555-6699* o! P5 {" t4 I
555-6480
8 h! R! v, R/ P8 [555-2127
5 N! B: O1 K, M7 \: o) Oregexp 也能使用在比较的算式。
) ^; }, p" u, M+ ?) [exp ~ /regexp/
3 p/ D6 W& K5 {8 L如果 exp 符合 regexp,则结果为真(true)。. ?9 t$ \& [3 I% u/ r: A' g
exp !~ /regexp/* B1 A' F- `. l8 ]
如果 exp 不符合 regexp,则结果为真。/ }; [) I# w7 B! k- ~5 Z$ E0 N
! ?3 q5 j- v! ~) |4 J
5.3 比较的算式当作Patterns
' P2 s# Z/ p: c6 h2 f6 s. I; A比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於
9 R+ L7 {2 ^7 y、小於。下面列出一些比较的pattern:+ X4 m! e- l# S
x<y 如果 x 小於 y,则结果为真。6 g: Y' Z: D" w0 z3 ^
x<=y 如果 x 小於、等於 y,则结果为真。
9 y n# R, v. t9 R+ ]( p+ b- o, xx>y 如果 x 大於 y,则结果为真。/ F% ]; Z9 r' |9 }: ?* H( d
x>=y 如果 x 大於、等於 y,则结果为真。) M$ k6 i8 C/ B) r* O: W0 ?
x==y 如果 x 等於 y,则结果为真。
3 @1 ~" } V$ Z' i" Mx!=y 如果 x 不等於 y,则结果为真。+ i. `3 I5 h# g+ r: z
x~y 如果 x 符合 regular expression y,则结果为真。
( E; f; ~2 O7 e6 {4 mx!~y 如果 x 不符合 regular expression y,则结果为真。- x1 r. X+ @' w* n) ^% z$ g' `
上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,
6 ~+ s$ `" D; D" {. T否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,
( R& z$ b$ a, ?( w I会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同
* o2 { |8 t% B( b! U的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视' f8 Y+ T7 b9 b, \7 `- j
为长的字串比短的字串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。: I6 O ]- \9 B' t# H
6 \( s# }7 p P" }5.4 使用布林运算的Patterns3 c; a) `0 x9 x8 ^% i# [" w
一个布林(boolean) pattern 是使用布林运算"或"('||'),"及"
, R& Q/ e* c, {9 \5 e/ B('&&'),"反"('!')来组合其它的pattern。' f+ }% A+ d- r. S3 K
例如:
- k" X$ B4 X9 zgawk '/2400/ && /foo/' BBS-list) }4 F( ~( f! C C- R" H' @
gawk '/2400/ || /foo/' BBS-list# p- f3 T) I. Q: X& S
gawk '! /foo/' BBS-list( b7 A$ ^+ o5 ]# \; z+ ^5 P' {
- [, k o# I4 G6 |7 [第六章 算式(Expression)作为Actions的叙述: C3 a1 ~( I6 c6 P
算式(Expression) 是gawk程式里面action的基本构成者。0 n& I! H/ d4 V* y
! K0 | Y# i1 P4 ^
6.1 算术运算
2 }2 k: w" L L2 C) t. agawk 里的算术运算如下所示:
& \2 ~+ E C ?9 Mx+y 加" { q: H* b9 S7 V0 T2 u9 D' ~4 b
x-y 减$ R" G1 }4 l9 {( _$ p' U
-x 负/ ^# B, {1 _4 i3 H* l
+x 正。实际上没有任何影响。0 j* Y, G7 |% M4 s
x*y 乘* D6 O$ |( H& V. i8 h& c/ m" R, j
x/y 除
/ \4 e9 B* l( k/ [: b: a# \, wx%y 求馀数。例如 5%3=2。2 j, U# ~, X6 u3 q
x^y
2 N: W H; E" J3 ^x**y x 的 y 次方。例如2^3=8。
% B6 u& Y- X. }* j* N6 ?" u( s$ I3 I! ?6 s, K
6.2 比较算式与布林算式
2 R; ^6 s& p# b6 {比较算式 (comparison expression) 用来比较字串或数字的关系
: D; o7 \* Z- V* Y! b,运算符号与 C 语言相同。表列如下:/ w, [! C; ~; ]# |6 N. a: ]
x<y
; P# g3 _4 v4 F- a$ px<=y! G2 _) d7 z, \/ c
x>y' g7 g, Q7 ?- _' l
x>=y, C) V/ V _: V t* w
x==y
: [) s, R& l* h" R/ Ux!=y
6 h0 \. I; |9 \. G. M% @$ ex~y7 |0 u; i( b7 M/ N
x!~y
* w' ]1 y# N6 G7 v, X比较的结果为真(true)则其值是 1。否则其值是 0。
. u, P! A7 D" F( n布林算式(boolean expression)有下面三种:
1 U5 y1 ~9 _, L0 \, q% bboolean1 && boolean28 M9 ?( y2 Y$ D( q6 l
boolean1 || boolean2
" `7 z: |9 g' i0 W/ c S, { [5 E8 P! boolean
) C0 H5 v( l o F! L
7 [3 V7 C" d1 Q7 e1 K% P6.3 条件算式(Conditional Expressions)7 ?; t1 p" S/ h$ h+ b; M" s( p Y
一个条件式算式是一种特别的算式,它含有3个运算元。
2 L& |' [$ w1 S% a* X! }- X& [条件式算式与C语言的相同:/ u o* Y$ L% ~ n5 u
selector ? if-true-exp : if-false-exp
! k- d" b) {& }- C$ N+ R它有3个子算式。第一个子算式selector 首先会被计算。如果是真,
& |' r1 ?; k# S# E. u/ V, O则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-
$ ]+ P9 `4 J& Lexp 会被计算且它的值变成整个算式的值。
7 T9 ~7 h, q& g例如下面的例子会产生x的绝对值:
$ ]# D$ {& _2 ^5 C& J* ax>0 ? x : -x
. e( E$ z1 }/ ~
1 R: O" A# e* P. ^+ d! \第七章 Actions里面的控制叙述
& k+ \: q3 J$ o$ W8 Q# T在 gawk 程式里面,控制叙述诸如 if、while 等控制程式执行的流9 ?$ o* R7 |, t# N% j
程。在 gawk 里的控制叙述与 C 的类似。: b# \% U" f2 A% M2 G0 {: s
很多的控制叙述会包括其它的叙述,被包括的叙述称为 body。假
0 Q1 `; A& v3 t) j/ D. s6 U如 body 里面包括一个以上的叙述,必须以大括弧 { } 将这些叙述括起- z2 S& ^+ Y2 r) x" g$ e# {: G
来,而各个叙述之间需以换行(newline)或分号隔开。5 q9 v" J" [7 i- G' ]9 c+ ~$ p
2 y& q4 |% J) k4 Y/ i7.1 if 叙述
9 b+ G6 k7 L1 Gif (condition) then-body [else else-body]
3 K$ n( n! k/ j3 J2 M: W; k, H如果 condition 为真(true),则执行 then-body,否则执行 else-body。/ B* O& a5 X0 [- C
举一个例子如下:: i! F5 R$ l1 E T7 K- E, T
if (x % 2 == 0)# ^) e' C Q) _& }
print "x is even"0 s3 f4 u7 b+ y! G9 h
else
6 Q: t1 {0 y, _print "x is odd"$ Q$ ^+ P/ D( Z$ X
9 N! i1 ^& S" \0 l' h( D2 W
7.2 while 叙述1 `+ w0 s0 g( p5 ?1 k+ o
while (condition)' p& |* l2 P2 N2 _+ [! a" Z: i
body. g" ~# j& v9 {' c, w
while 叙述做的第一件事就是测试 condition。假如 condition 为真则! z7 c3 ^6 T* i! H# i
执行 body 的叙述。body 的叙述执行完後,会再测试 condition,假如
; H' |" V: H, B- |condition 为真,则 body 会再度被执行。这个过程会一直被重复直到0 g7 S2 t" p/ n/ ^+ d
condition 不再是真。如果 condition 第一次测试就是伪(false),则
* A+ `5 I# ]6 E$ e: V6 V* \$ x6 abody 从没有被执行。
; S) A3 ~3 ?7 r; f4 ~9 O) Z# i5 m下面的例子会印出每个输入记录(record)的前三个栏位。
, B) x& T) Y" d: b& x- K% d) Y9 F0 Agawk '{ i=1( u2 x; i# M2 V2 E
while (i <= 3) {% I2 N0 R6 u" B' ^. t; Z9 w
print $i
6 j# e. e+ a, ]& c3 ?i++6 K' Z# w! v' x- y
}3 Q- `3 L% f' `% `" P
}'7 p/ @. @- V) w) z
) D5 ?5 B% b/ q8 F; ?7.3 do-while 叙述7 o% F [& r) ~9 n9 ^, L
do
. `9 z6 _; W/ e; d+ S' Zbody3 U) F" N% u& f! B* E7 J F
while (condition)) K4 M% s! Z. G+ p3 h! P; o
这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。; _" H1 A0 t+ G9 O9 t
即使开始时 condition 是伪,body 也会被执行一次。
" j* h7 s$ V1 ~下面的例子会印出每个输入记录十次。
# W5 J0 H- D) }gawk '{ i= 13 L6 j* q: A- K0 L1 Y3 l
do {, Y- ~1 g7 `& J9 P" `5 H, N0 _
print $03 t! ?% f- a+ `* ~
i++
( L6 _5 V5 U& W; x# I" E" C} while (i <= 10)
5 j* {* d* G( g* ?$ ?: N; V}'
2 s3 F3 l. u7 H+ G6 P8 C9 f8 @- t# N& ^1 m
7.4 for 叙述
7 ]3 X, Q: t% |- n+ r3 J0 a6 \" Q; c+ bfor (initialization; condition; increment) ~% a; d+ Q/ X
body, \6 ^+ }& i3 e" z2 X/ p3 ?
此叙述开始时会执行initialization,然後只要 condition是真,它
6 `5 |7 Q( F7 g# f; B( J会重复执行body与做increment 。
. n% ^2 \5 T8 c' @下面的例子会印出每个输入记录的前三个栏位。+ x8 ^3 Y6 [: h/ R) \# x0 R0 ^
gawk '{ for (i=1; i<=3; i++)# h5 S' b: J- m4 `) l" {2 s7 J
print $i- s3 w2 w! q! e
}'
0 Z6 i2 S3 ?2 U' D# C$ ]' P ]* K6 u
7.5 break 叙述2 t9 c$ W. _8 p8 u
break 叙述会跳出包含它的 for、while、do-while 回圈的最内层。
. q. W1 _% w, o0 }* [$ I下面的例子会找出任何整数的最小除数,它也会判断是否为质数。
/ `% U: h7 l W4 p* jgawk '# find smallest divisor of num* Q0 H" H/ w# e; @
{ num=$1
6 X& _ @4 v) \: ^for (div=2; div*div <=num; div++)
+ p+ K" p3 K+ @& B0 e: kif (num % div == 0)
3 e* Z/ d( y' t1 W. qbreak
7 L! N0 p( P8 E) D# pif (num % div == 0)
! }; J# r9 w6 vprintf "Smallest divisor of %d is %d\n", num, div
# j( ~" H: K2 P0 z! K) z; Qelse
0 `; I6 I+ M! f/ |* Y: R* \printf "%d is prime\n", num }'8 D! W0 y7 m# ]! p
, ^5 U: g$ L5 D4 U9 D7.6 continue 叙述5 d) F5 s; t" G6 N: w
continue 叙述使用於 for、while、do-while 回圈内部,它会跳
9 m, c9 H" [! F( O6 M" o: [过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。
) a$ I5 Y8 Q; A& s0 q$ F2 ~下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。9 Z5 w6 o# I7 V
gawk 'BEGIN {
3 V9 S6 J' Y' J% _6 Q/ lfor (x=0; x<=20; x++) {
2 G+ F! x. U5 C' n2 z" P+ gif (x==5)4 @8 i0 ?5 k. z! | x2 I& b
continue& ? `, b4 m( S I. A" d) x
printf ("%d",x)! h4 f( b! u, M8 n+ e* O2 y- b+ J
}
: B/ ^3 ?5 t( b8 e& E' I6 J* gprint ""
W* a1 Q7 r% C& J8 W}'2 w. N) M5 D+ I- G; k4 L& t1 ^7 X
4 X4 r+ ^2 j- B# }' P0 s7.7 next 叙述、next file 叙述、exit 叙述
; K: v+ Y z- e0 a4 k2 Unext 叙述强迫 gawk 立刻停止处理目前的记录(record)而继续下一
2 P, P8 v U: y: U8 N+ \个记录。
+ S7 y+ }5 X9 O1 }; T' fnext file 叙述类似 next。然而,它强迫 gawk 立刻停止处理目前
7 `. P6 `# }4 I$ A( J1 R的资料档。2 o5 ~5 r1 s+ x' { `- }
exit 叙述会使得 gawk 程式停止执行而跳出。然而,如果 END 出现$ M* h3 g) v! Q/ x
,它会去执行 END 的 actions。& y7 C: q& o0 c' s8 v0 v1 ?1 l( ?
( l3 [4 H1 N. h# ?+ p! Y
第八章 内建函式(Built-in Functions) |5 J. f: @& D% c! |
内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建3 X: u H4 _- P& i$ F# s9 T, Q
函式。
: {- ?/ l$ e% j r9 H2 V8 J
& L6 n" P6 B" }# z% \( `8.1 数值方面的内建函式
g3 b* Z, U: P* x. I- Jint(x) 求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9)) O: G1 S! C4 @' \# }( T9 E/ v
是 3,int(-3.9) 是 -3。" ]3 e* Z, [6 i& a
sqrt(x) 求出 x 正的平方根值。例 sqrt(4)=22 m, { x0 ~; e( ?* R5 G. L2 p
exp(x) 求出 x 的次方。例 exp(2) 即是求 e*e 。# Y* Z$ u3 v+ P0 I8 w
log(x) 求出 x 的自然对数。5 f, T& n$ O8 Y# S8 {4 F
sin(x) 求出 x 的 sine 值,x 是弪度量。6 p2 z" u) L. c
cos(x) 求出 x 的 cosine 值,x 是弪度量。
0 s' O$ H6 X6 d |) g$ Tatan2(y,x) 求 y/x 的 arctangent 值,所求出的值其单位是弪度量。: A5 Y8 ?4 u6 W! Y2 g) B3 ~
rand() 得出一个乱数值。此乱数值平均分布在 0 和 1 之间。这个5 y# q! k6 d6 \8 m4 `( a
值不会是 0,也不会是 1。
0 R0 k6 r+ G; J4 ~9 [$ b每次执行 gawk,rand 开始产生数字从相同点或 seed。
1 s. G5 H& Y+ C7 F8 Msrand(x) 设定产生乱数的开始点或 seed 为 x。如果在第二次你设# }4 E7 @+ |% e
定相同的 seed 值,你将再度得到相同序列的乱数值。
c. o7 B& ~# i. k5 C如果省略引数 x,例如 srand(),则现在的日期、时间会% {3 s6 {# h" \4 o0 K# {
被当成 seed。这个方法可使得乱数值是真正不可预测的。
. C4 U2 _0 M: ^$ esrand 的传回值(return value)是前次所设定的 seed 值。
" w5 w3 v) h) ~! b/ l6 x5 c- c2 A$ c6 v1 i$ b+ a1 A) C% f
8.2 字串方面的内建函式# @5 C' W. q- ?" d8 l+ r( `! l
index(in, find)
1 D' f4 @* z' l" P2 w它会在字串 in 里面,寻找字串 find 第一次出现的地方,传回值是
" Z3 r& h- ~+ s* J8 R( K2 y字串 find 出现在字串 in 里面的位置。如果在字串 in 里面找不到字3 T' [6 }9 ^* ]# M
串 find,则传回值为 0。
% C( G: n8 _$ u3 l+ d& L+ ?( G例如:4 }: |& b" P$ M& X# u
print index("peanut","an")
2 W. \+ O+ E' c/ @- r2 r会印出 3。
8 s9 r4 Q: a, J L' b3 @length(string)
, M- n7 i& k) ^求出 string 有几个字元。
5 O4 U; t- V4 H, V; \6 k. r例如:
# t; P& q8 X7 X( ^ @3 \9 @length("abcde")
2 \: z7 y+ e9 J; B! N7 a+ f是 5。! b* T0 v+ L# s w% r
match(string,regexp)
, N# V0 e, r) a! {9 K$ ?0 Y. lmatch 函式会在字串 string 里面,寻找符合 regexp 的最长、最靠3 `; Q" f# L) Z6 \
左边的子字串。传回值是 regexp 在 string 的开始位置,即 index
3 ]% x' V8 d/ W1 g$ m& R9 A9 p值。
6 c2 ^" T. n* e4 r2 n& _( {/ Xmatch 函式会设定内在变数 RSTART 等於 index,它也会设定内在变, c: @2 d& {6 X2 y2 T7 `4 v
数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为; ^& s3 t1 Q) i- I0 A) R
0、RLENGTH 为 -1。
6 }" t9 z6 C/ ~: Nsprintf(format,expression1,...)7 x* K4 } {- s& G/ x8 w
举 printf 类似,但是 sprintf 并不印出,而是传回字串。1 k { ^. v. ^4 D9 ~6 t
例如:9 z3 \5 X# p( O% E0 i) e& ]+ ^
sprintf("pi = %.2f (approx.)',22/7)4 l7 d" |) g2 Y2 p/ t; ?
传回的字串为"pi = 3.14 (approx.)", g: j P& X8 J+ u
sub(regexp, replacement,target)
7 ?! u9 ~" W3 E- `# b在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,
& m3 z1 k0 R2 M以字串 replacement 代替最左边的 regexp。
2 z% `; U, b1 N. C例如:) E+ W% b6 j" P' g c- ^% i
str = "water, water, everywhere"3 W0 D# W- y7 }
sub(/at/, "ith",str)2 _. j, u3 `. k1 L, v# D! K
结果字串str会变成
6 k9 q# H3 W" R4 N"wither, water, everywhere"
" I B; g5 ~% y L Pgsub(regexp, replacement, target)
/ K) g+ F) P& Y7 L8 Qgsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的 H! R2 c0 t; F G" W
所有地方,以字串 replacement 代替所有的 regexp。9 W! F8 \& A; Y% P6 F$ N
例如:0 ^% f4 N/ ?# P/ T. }9 J
str="water, water, everywhere"
$ e0 [# V, E, A8 Lgsub(/at/, "ith",str)8 c f* `5 ]. H* X* `9 N* R
结果字串str会变成7 T8 o9 K8 h' Z# r c4 @& P( M7 \0 ?
'wither, wither, everywhere"" k0 Q: |$ E: ` l) R v
substr(string, start, length)5 J; k" m) l2 c
传回字串 string 的子字串,这个子字串的长度为 length 个字元,$ n8 f8 i9 h J! i9 E# f" G' Y
从第 start 个位置开始。4 h: N8 w2 ~, G3 e
例如:
: E% F: w/ q! F) l2 U* tsubstr("washington",5,3)
" z) Q& M# F( R/ v O7 J传回值为"ing"
& c% X! |) l; N" u" |( J# _如果 length 没有出现,则传回的子字串是从第 start 个位置开始/ H; Z! ~$ {: c4 Q
至结束。
: l% a3 p4 O5 A7 r5 l例如:
, D, R6 L D# ^, ?substr("washington",5)
% `. s! h6 d/ B1 z% m- H传回值为"ington"
+ U) I$ O5 J. [; m5 e. qtolower(string)
8 r" A, U& e0 O) R: R2 t将字串string的大写字母改为小写字母。2 G0 `( F2 R3 v' F _& h4 }5 w. o! L& Z
例如:
3 J2 c5 ~" A) ]7 h* Etolower("MiXeD cAsE 123") |/ L' r+ V$ u, d. d
传回值为"mixed case 123"
, w# O' |: }* i4 z6 x N: Ztoupper(string)
9 C6 @: G$ C, n/ z% c) r* M将字串string的小写字母改为大写字母。
/ j; |- g m O例如:2 Q& ~3 A. x* b2 M' Q
toupper("MiXeD cAsE 123")
8 l' b7 f) m2 G; x! G$ ^9 n5 X) k传回值为"MIXED CASE 123"
U( r" c- s: V! t" V: C& J @$ D0 \/ H
8.3 输入输出的内建函式, @5 }2 Z/ C. j" {7 x5 H* h& r
close(filename)
1 m8 c2 \3 A$ i3 ?. R将输入或输出的档案 filename 关闭。
2 Q4 b! p1 b5 D3 Osystem(command)
! Y1 { e6 ?( S此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk
) f4 N+ F1 i6 _4 v) j程式。+ u8 ]" w8 Y% H7 z; U6 i$ B2 S
例如:
: L7 I8 `/ \( D- a3 ^ uBEGIN {system("ls")}* L( f |- ]5 z
& j W! Z: `# y5 D& B1 D第九章 使用者定义的函式(User-defined Functions)$ W3 e# N/ I+ s* {5 m
复杂的 gawk 程式常常可以使用自己定义的函式来简化。呼叫使用 v7 S* `& w$ G k# p
者定义的函式与呼叫内建函式的方法一样。9 k' K- h% }4 W+ q/ K4 W
9 a: q# Q: @2 L2 b* z
9.1 函式定义的格式/ ?1 x( n9 o5 V4 c- j- L7 s1 W; l
函式的定义可以放在 gawk 程式的任何地方。
/ }9 I/ \2 \( w# n$ W' c3 {一个使用者定义的函式其格式如下:1 T- P# T# j4 y
function name (parameter-list) {
8 K+ R$ R: _) l: _body-of-function
2 p7 |2 Z& I7 |" l% u0 M+ z}% m( j1 l" {. K0 u# o
name 是所定义的函式之名称。一个正确的函式名称可包括一序列的字
4 J9 X% O0 z1 o+ R母、数字、下标线 (underscores),但是不可用数字做开头。
( T+ k3 B; x) X3 O. V% uparameter-list 是列出函式的全部引数(argument),各个引数之
2 r) ?4 y8 Y# Z( N7 b; P, A" u, }间以逗点隔开。" v5 g9 F8 h; _. V
body-of-function 包含 gawk 的叙述 (statement)。它是函式定义
* j$ q- O9 D, e% G$ l* U9 g里最重要的部份,它决定函式实际要做何种事。( S. U- E( L3 F+ `/ i
7 R' @, g% x$ T4 ~9 A: H" N6 ]% n9.2 函式定义的例子
5 d" ^$ A5 ]6 W: m( P. `下面这个例子,会将每个记录的第一个栏位之值的平方与第二个1 X7 a8 K0 z/ Y7 o- g* ^
栏位之值的平方加起来。
d+ X1 `7 A& _& W, ?{print "sum =",SquareSum($1,$2)}
8 s7 v! W- B) p5 Z$ F efunction SquareSum(x,y) {6 T' L# e) |( w! o6 {
sum=x*x+y*y4 D w9 [: _9 _8 l; h7 q
return sum
% i- ~: q* k3 ~}
$ C! n0 w5 {/ e0 p4 O& w. P) B( R$ L7 z0 y3 H: }! l. s6 K
第十章 □例0 ~& N. X8 X2 H7 W7 V; j5 Z
这里将列出 gawk 程式的一些例子。; B" C: F; \7 C7 o( k
gawk '{if (NF > max) max = NF}; |+ V* y- k% d7 @0 e" V
END {print max}', {, h6 O) X! u6 @( e- J% h
此程式会印出所有输入行之中,栏位的最大个数。" B5 g- _8 O, {
gawk 'length($0) > 80'2 ^, y# E; n. w% P0 [ w" S
此程式会印出一行超过 80 个字元的每一行。此处只有 pattern 被; x0 ]+ s' a8 _9 G T7 B9 h
列出,action 是采用内定的 print。. i# B* H2 L! z- o
gawk 'NF > 0'4 F7 S& t# _( c# T% f* R; E# [
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简" C o5 L; ^: @8 f" i- m: d m
单的方法,将一个档案里的所有空白行删除。
0 g `( w6 I! l* m; wgawk '{if (NF > 0) print}' _- w5 B$ O9 ~3 B0 U
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
" C( K$ r& N& @单的方法,将一个档案里的所有空白行删除。
M$ f1 g- V# @2 j& L$ k: Xgawk 'BEGIN {for (i = 1; i <= 7; i++)
1 W o7 D9 H" X# }print int(101 * rand())}'
! Z0 ~ G# h: ?8 I3 I$ u4 [# Q此程式会印出□围是 0 到 100 之间的 7 个乱数值。
6 F' f( \( A" Y' r$ J2 L5 D& m1 Bls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
- R( z. o9 Z4 _# w0 I% v+ e此程式会印出所有指定的档案之bytes数目的总和。
: U' n: h" s( j- z6 j% u) ~7 ^expand file | gawk '{if (x < length()) x = length()}5 Q4 B+ Y1 S2 C
END {print "maximum line length is " x}'
) g( |+ a& |+ `2 |. o; B8 W此程式会将指定档案里最长一行的长度印出。expand 会将 tab 改
7 \/ b5 R0 Z7 T3 U( @# b+ g3 A: L成 space,所以是用实际的右边界来做长度的比较。
9 Z; ~7 a/ o t( w% O; ngawk 'BEGIN {FS = ":"}+ ~$ q% }$ V9 V) x# x5 o
{print $1 | "sort"}' /etc/passwd4 K2 S8 H% b- |6 ^ x' ^/ g0 L
此程式会将所有使用者的login名称,依照字母的顺序印出。
( K% T3 h3 i- U9 c! R' Mgawk '{nlines++}
. [ H' c2 Q' `: FEND {print nlines}'& W& h; u! [$ ^! g
此程式会将一个档案的总行数印出。+ ? C$ M2 D P" S' T
gawk 'END {print NR}'0 B8 E7 t+ v5 ` T l
此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk4 x T; S3 p! A: } S
来做。
% d, v" P& l6 n1 P, |gawk '{print NR,$0}': Q) b. N$ a; v5 i
此程式印出档案的内容时,会在每行的最前面印出行号,它的功
o) w$ m& M9 i+ c# b能与 'cat -n' 类似。7 Y. K6 n; ~# e1 h( z# W& Y" d
) U6 a" \: _5 A/ ^7 r* `
第十一章 结论! h: {4 G. V$ D2 y$ v
gawk 对於资料的处理具有很强的功能。它能够以很短的程式完成
6 D* {/ E5 v2 p2 L( a' o% M想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件
6 I- L) [; m: A工作,以 gawk 程式来写会比用其它程式语言来写短很多。
; L' v# [1 H/ {& i; ^' C ~gawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使* P8 A9 o7 R+ C9 e
用。 |
|