TA的每日心情 | 奋斗 2019-2-12 09:32 |
|---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到 累计签到:1 天 连续签到:1 天
|
马上加入,结交更多好友,共享更多资料,让你轻松玩转电力研学社区!
您需要 登录 才可以下载或查看,没有账号?立即加入
×
GAWK
# R. ]5 x8 d9 x$ K% A! Q第一章 前言4 p2 S$ L& U, s( |: l0 Y
第二章 简介1 F* C' {! e( j9 H0 ~
第三章 读取输入档案, Q+ z! D E" E8 b! x/ x! `
第四章 印出
0 E+ @9 Q8 z* ~# a! V% c1 c9 X; w第五章 Patterns4 d% I# C0 `* V+ Z: M5 K/ u
第六章 算式(Expression)作为Actions的叙述$ n. X% H+ X/ j- o6 M! w
第七章 Actions里面的控制叙述
. Z" v8 l- S7 P7 G第八章 内建函式(Built-in Functions)
; E& P; i5 k" C& s3 M. g6 D3 F! M第九章 使用者定义的函式$ P, T7 i+ D1 y
第十章 □例3 ^2 L$ d3 t6 D3 D8 x/ z' {, I" R
第十一章 结论9 w$ r4 j9 s2 D) P5 [* q
# W7 |7 x* B; h8 B# I=======================================% e) K6 |) r% }3 ~. x
第一章 前言$ z' F1 b# M% b( H! Y/ @
awk 是一个程式语言,对於资料的处理具有很强的功能。对於文
3 }" R4 W* V& T' E7 e字档里的资料做修改、比对、抽取等的处理,awk 能够以很短的程式* W0 D. N' g, R1 q
轻易地完成。如果使用 C 或 Pascal 等语言写程式完成上述的动作,
* Q( I3 d9 G8 ]; L# r4 `; H会不方便且很花费时间,所写的程式也会很大。
# S3 p& A. v# S- Oawk 能够依照使用者的定义格式来分解输入资料,也可依照使用8 k% `/ q; g7 [5 B3 h Z
者定义的格式来印出资料。
/ R2 ~/ j( N, v- b5 S; L) nawk 名称的由来是由它的原始设计者的姓氏之第一个字母而命名
, H) x) g$ F0 P0 {, T6 }7 M:Alfred V. Aho, Peter J. Weinberger, Brian W. Kernighan。7 m! n# ?0 P( X
awk最初在1977年完成。一个新版本的awk在1985年被发表,它的功能
+ z1 R, T7 G* |2 T& h0 h比旧版本增强不少。
* X( h4 h8 `( c" w3 z5 B `7 w4 Tgawk 是GNU所做的 awk,gawk 最初在1986年完成,之後不断地& ^# T* _; K/ X8 A4 d9 i/ c% i
被改进、更新。gawk 包含 awk 的所有功能。
$ g. h! v6 T1 n1 N! h. ? q往後的 gawk 将以下面的2个输入档案来做例子说明。
4 u0 b( N+ c" G7 X) U档案'BBS-list':7 B; W! e, A+ u: @
aardvark 555-5553 1200/300 B A( |( J7 U5 q& `, |% ^* }
alpo-net 555-3412 2400/1200/300 A
5 ?4 j1 B7 O: H* Abarfly 555-7685 1200/300 A, \' v7 @ {% b2 d9 H
bites 555-1675 2400/1200/300 A
$ c- F, r. Q5 w2 ~5 Ncamelot 555-0542 300 C
+ W& q9 Y4 r/ r6 y. T/ T# kcore 555-2912 1200/300 C
6 F1 A) O9 R, y0 ~* ]fooey 555-1234 2400/1200/300 B
. y) J c- x7 O0 r% ?, pfoot 555-6699 1200/300 B
0 e! D4 L, f' _4 @macfoo 555-6480 1200/300 A! u0 m% B( G# W7 W" T5 [' P
sdace 555-3430 2400/1200/300 A4 C/ \6 p) y8 g; J
sabafoo 555-2127 1200/300 C
4 U7 \8 P% I4 B! v档案'shipped':1 k1 z+ \" y2 b* g# n
Jan 13 25 15 1153 ]4 v+ o$ _; _6 f& _/ ]! x
Feb 15 32 24 2269 t" d; G2 P( [, X" |& A- I: R
Mar 15 24 34 228
: `8 F! h1 ?' C7 C( Z1 j& ZApr 31 52 63 420
2 S; a M* j/ ]" b8 e* M; [May 16 34 29 208
# U& W/ ^" Y+ zJun 31 42 75 492
9 t1 T, N) f8 C. A) oJul 24 34 67 4364 c* N J2 R Q+ P3 V
Aug 15 34 47 316
( @4 a2 L) ]4 mSep 13 55 37 277
3 n0 x9 \/ ~" P: w! X/ ~$ dOct 29 54 68 525& b; i# m& C3 k3 d4 b; b6 p' _
Nov 20 87 82 577! G' I6 d1 F( Y4 k% J }7 ]
Dec 17 35 61 401) X1 Z- M- j( y2 C3 T' d
Jan 21 36 64 620
" K, R$ ?# p" E. ~& `& [3 U& YFeb 26 58 80 652, d# k* J$ a8 J# c6 R) p7 D
Mar 24 75 70 4952 F; S9 n+ T! O1 a' N- I* W
Apr 21 70 74 514
, R, f# T7 F3 o6 I. S
8 A6 E, y( H* n; `第二章 简介' S5 q: k3 N! b& H2 k
gawk 的主要功能是针对档案的每一行(line)搜寻指定的 patterns
% p+ T" @' `9 G6 F- B。当一行里有符合指定的 patterns,gawk 就会在此一行执行被指定
: A4 s& i+ e0 E0 }的 actions。 gawk 依此方式处理输入档案的每一行直到输入档案结
$ f5 r4 O6 h2 X; l6 e束。
: S9 s6 _7 k6 n' k7 U* H4 X- Dgawk 程式是由很多的 pattern 与 action 所组成,action 写在
# ~7 @# [5 y, t M: l/ g. d% G/ H大括号 { } 里面,一个pattern後面就跟著一个action。整个 gawk 程
# E- M8 r1 ?# ]) e" Y( U2 N式会像下面的样子:
/ g. n/ }* B' N0 j4 X& K- @) ppattern {action}" Y1 I" l* `. X7 S W3 A
pattern {action}
* f4 n1 Y m0 S& K5 r在 gawk 程式里面的规则,pattern 或 action 能够被省略,但
0 _6 @- z3 b. n' f+ }是两个不能同时被省略。如果 pattern 被省略,对於输入档里面的4 S4 T) W+ c# u
每一行,action 都会被执行。如果 action 被省略,内定的 action
. D5 z2 I" z: ?! N' m5 ~1 V$ L! G* }8 ^则会印出所有符合 pattern 的输入行。2 Z/ ?4 ^4 m1 N1 _7 F% R
* y1 r/ v7 t1 v& d' q) A2.1 如何执行gawk程式
3 y% _& w$ n# @5 J- ~$ {4 ~基本上,有2个方法可以执行gawk程式。
8 }; P+ d* e/ ^& `/ ~2 g O□如果 gawk 程式很短,则 gawk 可以直接写在 command line,如下所示:8 G5 Q# r' h2 t' j# V# r6 o( |* o
gawk 'program' input-file1 input-file2 ...
4 j7 G3 B" Y# j% d/ D+ b5 d其中 program 包括一些 pattern 和 action。; b2 o& ^* P" o+ ?
□如果 gawk 程式较长,较为方便的做法是将 gawk 程式存在一个档案,
% {3 i7 Z5 J5 q6 c0 b Q' U0 @即 patterns 与 actions 写在档名为 program-file 的档案里面,执行8 P# G4 _+ m) g
gawk 的格式如下所示:
9 d5 b; t$ i6 M. {2 ^gawk -f program-file input-file1 input-file2 ...# x J5 |6 O' B/ L# e
gawk 程式的档案不止一个时,执行gawk 的格式如下所示:
( p ?+ F4 D' O0 s& v- m t. Bgawk -f program-file1 -f program-file2 ... input-file1
* X) L& h0 d5 }5 M6 L; Oinput-file2 ...- ^% ^/ q/ b3 b/ {" a7 @
G5 e" p/ U& D$ b1 p( D2.2 一个简单的例子/ R) x) ^, u2 ]) y+ ?$ T) V
现在我们举一个简单的例子,因为 gawk 程式很短,所以将 gawk 程
9 P( e: |' W& ~% t' P. p- e式直接写在 command line。, z7 D% i6 q7 j+ X
gawk '/foo/ {print $0}' BBS-list
8 ^, ]' D, x( Z5 O: k, ?* x实际的 gawk 程式为 /foo/ {print $0}。/foo/ 为 pattern,意思为搜
- }) |/ b9 e. P3 r1 _3 Z* ^2 g; W寻输入档里的每一行是否含有子字串 'foo',如果含有 'foo' 则执行 action。- f9 o, s) Q4 c3 [+ x; {
action 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。" K2 @* Y9 Y7 e. R" ?
执行完上述指令後,会印出下面的结果:) O1 u- r2 z x- `: P! X1 _
fooey 555-1234 2400/1200/300 B
" \# s, g" x. E7 r! o4 ufoot 555-6699 1200/300 B
5 l+ A' P4 z1 l: cmacfoo 555-6480 1200/300 A) w& F5 R6 L5 X# u, G: p7 \. [
sabafoo 555-2127 1200/300 C9 z4 L; L* O- P I( Y
! V8 H2 O" D4 h: j9 p: \& ]" [4 B2.3 一个较复杂的例子
) {4 w B1 t, z4 M1 e$ vgawk '$1 == "Feb" {sum=$2+$3} END {print sum}' shipped
) n: i. D: A! r+ A2 {' i D现在这个例子会将输入档 'shipped' 的第一个栏位与 "Feb" 做比较
4 V7 a8 ~2 U, U! c& |,如果相等,则其对应的第2栏位与第3栏位的值会被加到变数 sum。
+ @0 {( ?1 C0 H/ z4 p" _对於输入档的每一行重复上述的动作,直到输入档的每一行都被处理8 x8 H+ B- p. F" r+ d
过为止。最後将 sum 的值印出。END {print sum} 的意思为在所有的输
: O) W3 D1 |+ j/ Q9 ?- ?. q/ a- u入读完之後,执行一次 print sum 的动作,也就是把 sum 的值印出。0 r! a6 r: X4 j7 z
下面是执行的结果:
P8 H' ^, d/ a* z84! G/ R6 \ k: ^/ S
- w# l: X0 i! t b; g第三章 读取输入档案 C/ \$ k3 P, k& B5 @2 e+ e
gawk的输入可以从标准输入或指定的档案里读取。输入的读取单5 H& g8 N& S L3 l: Z: ?
位被称为”记录”(records),gawk 在做处理时,是一个记录一个记
. a. c* ^0 W- v录地处理。每个记录的内定值是一行(line),一个记录又被分为多个
. Z# ^8 O, n, O7 a. O! r栏位(fields)。
7 f% d$ P! Z# l( l( s& U; x$ x) x0 [9 O
3.1 如何将输入分解成记录(records)4 ]$ B; @4 z+ F& }' R; }7 M1 q
gawk 语言会把输入分解成记录(record)。记录与记录之间是以
, n- L( j/ Z) d! U: _2 E2 |) u; q( yrecord separator 隔开,record separator 的内定值是表示新一行的
) T8 R' g: `% z5 {2 n& e字元(newline character),因此内定的 record separator 使得文字3 d- ^) z5 h' O5 |$ ?9 a, L" [
的每一行是一个记录。
a$ [# @) D) h$ v7 G9 X1 @record separator 随著内建变数 RS 的改变而改变。RS 是一个字串,
% k, ]; K- Q0 D, S它的内定值是"\n"。仅有 RS 的第一个字元是有效的,它被当作 record
( y$ O7 d7 Y2 D6 [# ~! T; Mseparator,而 RS 的其它字元会被忽略。
+ X4 h* F% l& k# t! e内建变数 FNR 会储存目前的输入档案已经被读取的记录之个数。内
. d% h# v7 ]: o5 F; v" Y建变数 NR 会储存目前为止所有的输入档案已经被读取的记录之个数。5 A Y. C' ]3 Y% q. u5 {9 U
: s# h6 e: m2 w. V+ {/ x6 q
3.2 栏位(field)
4 s [4 k0 T9 ~, J$ i0 \gawk 会自动将每个记录分解成多个栏位 (field)。类似於字在一
, X9 S, b6 T! ?3 G% {行里面,gawk 的内定动作会认为栏位之间是以 whitespace 分开。在9 x2 i1 k0 j% X/ `, u: @. C
gawk 里,whitespace 的意思是一个或多个空白或 tabs。3 T" G; F! D, j( K
在 gawk 程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位
* X- u: i% ]5 l: P& k,依此类推。举个例子,假设输入的一行如下所示:6 I g0 ]" m: s; X' X8 e
This seems like a pretty nice example.
0 ~% o* N# I3 L5 O. D1 y第一个栏位或 $1 是'This',第二个栏位或 $2 是 'seems',依此类推。
2 r; G4 i5 t4 Q$ n7 V有个地方值得特别注意,第七个栏位或 $7 是'example.'而非'example'。- L5 T# |, p: ~3 H# |4 }
不论有多少栏位,$NF 可用来表示一个记录的最後一个栏位。以3 {' |) R2 m ^3 p4 K
上面的例子为例,$NF 与 $7 相同,也就是'example.'。3 D5 }: M8 X" C+ h) ?6 s4 H( ~- D
NF 是一个内建变数,它的值表示目前这个记录之栏位的个数。( U* z1 L2 U4 D( R: j& o
$0,看起来好像是第零个栏位,它是一个特例,它表示整个记录。
2 {. n- Q/ K# r! l. X" c, a9 A下面是一个较复杂的例子:
4 K: n7 S# z: q6 ggawk '$1~/foo/ {print $0}' BBS-list2 I$ m! E( N" n9 ?( R# ^# I, A: k
结果如下:9 M+ x |- K* g, u
fooey 555-1234 2400/1200/300 B) n$ L3 K5 s' \5 p# K0 ^
foot 555-6699 1200/300 B
+ s/ u9 K1 b- wmacfoo 555-6480 1200/300 A% p3 i" j/ G1 c# I5 ~4 Z
sabafoo 555-2127 1200/300 C
7 [3 B6 `, v8 `- P这个例子是把输入档'BBS-list'的每个记录的第一个栏位作检查,如 z. W" m* s- V* B: l
果它含有子字串'foo',则这一个记录会被印出。
5 e* m3 R1 T: b
$ G2 U& J% r- \$ c6 T3.3 如何将记录分解成栏位+ Q* `0 `9 v6 I
gawk 根据 field separator 将一个记录分解成栏位。field sepa-
8 t6 G. @$ d! X$ [0 w1 z Q' G* f3 Grator 以内建变数 FS 表示。' K- _* S" M; P1 P" ^% m
举个例子,假如 field separator 是'oo',则下面的行:+ @$ k( G: ~9 X$ o- h% a
moo goo gai pan l: A# [# ~- C: R* y
会被分成三个栏位:'m'、' g'、' gai pan'。, z6 m w4 a" }( ?! n8 R
在 gawk 程式里,可以使用'='来改变 FS 的值。例如:" L: R3 T% B& ^: A d
gawk 'BEGIN {FS=","}; {print $2}'( q$ _0 i! w" R( f( l9 ]
输入行如下:
* E# [6 G; d+ H9 _John Q. Smith, 29 Oak St., Walamazoo, MI 42139
3 ]( P4 i, h; s! w+ e, j执行gawk的结果将印出字串 ' 29 Oak St.'。BEGIN 後面的 action 会在- W6 r: A. {+ ?/ `
第一个记录被读取之前执行一次。( P* j5 x( S+ Z+ Y# }1 }+ D
* G# M3 k) x9 r* \" W) c
第四章 印出) A0 J' F# o' J8 V
在gawk程式里,actions 最常做的事就是印出(printing)。简单1 W* J: Y7 K" p
的印出,使用 printe叙述。复杂格式的印出,使用 printf 叙述。6 A0 b2 T; ]3 E1 Q! N+ n+ N1 ~- z
: D% @$ q/ [! Y: N5 k. q- S4.1 print叙述
* z% A, [% c3 _2 }& jprint 叙述用在简单、标准的输出格式。叙述的格式如下所示:& T5 j2 P0 Z' { }9 l
print item1, item2, ...$ o# L/ T- b9 C, u
输出时,各个 item 之间会以一个空白分开,最後会换行(newline)。0 q7 b. ^3 Q6 I& g& j b2 a! i! L
如果 'print'叙述之後没有跟著任何东西,它与'print $0'的效
5 K# J# g( u1 u3 P: x果一样,它会印出现在的记录(record)。要印出空白行可使用'print5 J _1 P7 N+ R ^
""'。 印出一段固定的文字,可用双引号将文字的两边括起来,例如7 [0 Z. G7 U- x: p B1 {, o/ E
'print "Hello there"'。
* u0 @% s" P+ O$ J这里是一个例子,它会把每个输入记录的前二个栏位印出:+ l3 x* H" |; T
gawk '{print $1,$2}' shipped
, _3 {9 z$ u% V0 r结果如下所示:
1 J* q3 U% }8 P7 ~Jan 13
7 Q/ J. y! l. H& T FFeb 15
' z7 V+ R; {- u/ W4 `1 {- R1 ~Mar 15' f' p" B. B: Q
Apr 313 U( b# a& r8 Y" O
May 16, N3 H- Q" q# x1 d
Jun 31
( V% N% r- ?! T8 g% ^9 n* B" aJul 24! q5 [7 e4 i+ ]" z/ x( W; E
Aug 15
1 u' k" P. b" v7 m6 s0 G% JSep 13
9 X7 p( i$ W! i* S' l' M& FOct 29 O9 l5 ^4 {+ E" H/ D, e5 {/ n! y
Nov 20. D, Q9 I9 n7 c" h# {1 U9 @4 \
Dec 17
& J9 R/ d C2 h$ h9 V) `Jan 21
+ y+ m& K+ I% W8 p. sFeb 26" ~* w$ {# i; c6 t0 }9 j' h+ B. x/ }
Mar 24
8 G3 L6 R! J' y' ?# L% EApr 21! w/ y5 c1 ^; F+ z
. [/ s" [+ A; {5 d! u! [
4.2 Output Separators
) m# ~4 h: o! o0 Q' _2 w) x/ C前面我们已提过如果 print 叙述包含有多个 item,item 之间
) h* u5 t2 ]+ O" d用逗点分开,则印出时各个item会被一个空白隔开。你能够使用任何
1 F" b! C% o% a3 N0 |+ a( ~的字串作为 output field separator,可以经由内建变数 OFS 的设5 o# J1 Z% R$ `7 Y
定来更改 output field separator。OFS 的初始值为" ",即一格的8 w/ _& L/ v* o. U9 t
空白。
- P8 E8 O/ q1 } x' `# s整个 print 叙述的输出被称为 output record。print 叙述输4 l0 u8 M! F2 m) \
出 output record 之後,会接著输出一个字串,此字串称为 output/ |% o# d d' q: d/ \$ Y$ U
record separator。内建变数 ORS 用来指明此字串。ORS 的初始值
7 x, w5 M( f/ k3 b为 "\n",也就是换行。/ m3 S6 m; \. `1 v, G; B
下面这个例子会印出每个记录的第一个栏位和第二个栏位,此二( m" G" A+ `- |/ |8 [ Y( D8 _
个栏位之间以分号';'分开,每行输出之後会加入一个空白行。5 ^" `2 i3 D n1 \, S0 A
gawk 'BEGIN {OFS=";"; ORS="\n\n"} {print $1, $2}' BBS-list" W; F/ K. c$ V7 Q: Y" o
结果如下所示:
3 e7 ^- _7 U3 G- E/ B: waardvark;555-55533 K0 z$ H, p4 [. n3 N) W
alpo-net;555-3412
+ p) ~0 s2 K: Z( t: j( J, qbarfly;555-7685
/ J) q6 m3 G& G3 @$ }' t5 X7 Pbites;555-1675
5 U' e9 n) d& J0 `% O5 f" kcamelot;555-0542: g/ F* L8 x0 ^, G4 F$ M9 X8 x! e
core;555-2912( p# l* R* G, V6 p
fooey;555-12344 h8 r0 m+ q5 X$ G
foot;555-6699
- t2 W8 b Q1 J# v2 w* O/ jmacfoo;555-6480
) @2 n) a8 w$ ?0 Lsdace;555-3430
O& p* D8 Y5 _% esabafoo;555-2127) z4 r: z: \! g, s
4 t4 V! v- W1 `% I; Y+ \4.3 printf叙述
9 e. b$ }3 ^, ~printf 叙述会使得输出格式较容易精确地控制。printf 叙述可以
" R) @. @# N. q1 B$ u2 p+ y$ m指定每个 item 印出的宽度,也可以指定数字的各种型式。
* ]- P. b6 d' nprintf 叙述的格式如下:
5 U4 ^+ q- L; ?4 l$ S2 |: X3 gprintf format, item1, item2, .... N; K+ B: }3 H3 F. n
print 与 printf 的差别是在於 format, printf 的引数比 print5 k7 g' B" J5 F6 u
多了字串 format。format 的型式与 ANSI C 的 printf 之格式相同。
" X. l& b! n7 K5 R# dprintf 并不会做自动换行的动作。内建变数 OFS 与 ORS 对 printf 叙9 D+ ?8 Z# o; K, m# @4 N$ p
述没有任何影响。
2 f4 c$ F) R# N$ M! ~格式的指定以字元'%'开始,後面接著格式控制字母。
; t" n7 L3 q' `格式控制字母如下所示:2 r5 h7 ?: R# Q4 p% @& @/ b; U
'c' 将数字以 ASCII 字元印出。" p' s6 y" U" R4 q% T3 }
例如'printf "%C",65'会印出字元'A'。
; ]* G: q% O8 a1 k' l'd' 印出十进位的整数。! ^+ I0 A) ?$ k, h2 \9 s! y* k
'i' 印出十进位的整数。
I( C- T n' x! N! P'e' 将数字以科学符号的形式印出。
. j6 N8 O. f/ P5 l8 r: ~例如6 {* K) K' |( J* F) V* n5 f: R
print "$4.3e",19507 v9 M' a. P; z; @* A+ w. z( P1 |
结果会印出'1.950e+03'。+ w* K H* H# m
'f' 将数字以浮点的形式印出。8 I( n; x/ r. s
'g' 将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果$ M. c% g3 E& M9 Z9 l v+ G
大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印
5 Q+ ]; p7 d' Q' ^9 j出。: h" \- ?& X3 x3 T
'o' 印出无号的八进位整数。
8 D5 l9 d; y) ~" K& }, C's' 印出一个字串。; u* x! S l1 f% B& Y+ u
'x' 印出无号的十六进位整数。10至15以'a'至'f'表示。+ ?8 }0 Y" l) s% h7 u; b6 i# F
'X' 印出无号的十六进位整数。10至15以'A'至'F"表示。1 t0 A: ?1 I; I1 a0 [ q0 [2 s y! y
'%' 它并不是真正的格式控制字母,'%%"将印出"%'。- D/ f5 ^" g( k/ I# l
在 % 与格式控制字母之间可加入 modifier,modifier 是用来进一
" k) f. O/ Q; N# e" | e3 |; O) P9 F步控制输出的格式。可能的 modifier 如下所示:6 B) J+ C2 G1 O; u+ O
'-' 使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在
' T4 C/ P4 {7 `. H5 u6 ?被指定的宽度向右靠齐。例如:
2 s7 U* e1 O; t& o, \7 C: Tprintf "%-4S", "foo": B+ U4 |8 N8 p! S+ r. [
会印出'foo '。
0 A( {" `3 c! s7 Y' {, S'width' 这一个数字指示相对应的栏位印出时的宽度。例如:% }: x- G2 |+ i$ q3 W4 ?3 p8 L1 s+ j
printf "%4s","foo"# `! D4 ~/ K, Q' m, z
会印出' foo'。0 e. s) G9 q, W" J5 K3 T1 U
width 的值是一个最小宽度而非最大宽度。如果一个 item 的
8 W4 `1 D$ a. j/ F6 ^( o值需要的宽度比 width 大,则不受 width 的影响。例如+ D8 X- v: \1 a K6 b* g1 A
printf "%4s","foobar"$ a& J. B6 C1 ]/ q2 @+ j7 c
将印出'foobar'。1 s( Y* W* v2 p5 M" ?" V
'.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。如
9 l O3 N3 V! @) f果是要印出一个字串,它指定此字串最多会被印出多少个字
$ O8 N! S* i; n+ Q& v. _8 r: k元。4 x7 ?' U# M: M0 Z+ r( N. q
8 F5 Y3 I, i- l8 [8 m( d8 h( R第五章 patterns6 Q1 e( ^2 d4 B1 ^- _7 W% G1 ?& \
在 gawk 程式里面,当 pattern 符合现在的输入记录(record),其
. b- T9 k3 u7 {% r8 \: v相对应的 action 才会被执行。
3 K+ W3 u3 Z* Y
2 f! H5 H$ F$ @" j$ p5.1 Pattern的种类' k W; R+ v! ?6 J4 A* M+ w7 v
这里对 gawk 的各种 pattern 型式作一整理:
( u" s6 A7 G$ e! |3 m" R8 e" S/regular expression/
. J0 Q! ~' \ r5 O一个 regular expression 当作一个 pattern。每当输入记录 (
3 X. y6 W: @6 Nrecord)含有 regular expression 就视为符合。
! ?- e% g' G9 \( Sexpression: L7 p) E5 N- B/ W. F$ m! g8 S
一个单一的 expression。当一个值不为 0 或一个字串不是空的,2 A: E9 r: i; {
则可视为符合。
2 r& x% {2 P$ l1 o- wpat1,pat2 R: Q( ]% F8 b- y# N
一对的 patterns 以逗号分开,指定记录的□围。; a! H1 i0 o% z0 L' L% x
BEGIN' x; z$ `- _, r" y" Q4 |% B
END
( e6 P8 L4 q, w2 ] ?& C, L# w这是特别的 pattern, gawk 在开始执行或要结束时会分别执行相
" m, X" ~( t8 S2 K3 r对应於BEGIN或END的 action。
# r0 w1 f& V8 z# Ynull
" h, H! F- g( Q2 b9 {$ o这是一个空的pattern,对於每个输入记录皆视为符合pattern。4 }0 ]& U; s$ |
# s) \7 p9 j* ~* y; H, U% L5.2 Regular Expressions当作Patterns
; s6 Z' h+ Z, V4 x一个 regular expression 可简写为 regexp,是一种描述字串的方 f0 O: v5 k% x6 G0 ]
法。一个 regular expression 以斜线('/')包围当作 gawk 的 pattern。/ I \4 u5 S+ W- W( A3 Q; j# [
如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,0 V0 q$ m6 |. h, V+ w0 b2 W
对於任何输入记录含有'foo'则视为符合。
$ E2 Q9 H% m3 K下面的例子会将含有'foo'的输入记录之第2个栏位印出。7 g4 _; b$ u* _. x
gawk '/foo/ {print $2}' BBS-list6 C3 X; I! e1 s- I1 @4 p9 ^. E0 |' k
结果如下:8 ]0 K/ A, i* O& p* G, }' v
555-1234
! R O5 D* @" S( l555-6699- c4 w. l$ Z. j' O) T! j; X7 W: w
555-6480) L* K# k& S. z+ q; @) K( j
555-2127
2 D& W/ ^- g' w1 V8 N4 Q2 z& zregexp 也能使用在比较的算式。; k, A2 i; W' u3 s8 `
exp ~ /regexp/$ @, I- R8 j$ S" u% ^0 O( d
如果 exp 符合 regexp,则结果为真(true)。9 O: ]& Z1 o! o& Y( Q3 a" e! E/ G
exp !~ /regexp/
1 x7 J( Z/ J# r5 y5 `7 r* [. E( c如果 exp 不符合 regexp,则结果为真。1 q4 R t1 c5 Q+ @: G+ B+ k
8 @/ S- v: a6 ~8 E8 N/ s7 N
5.3 比较的算式当作Patterns
+ G* `" l% i# Y; ?! L5 ~$ q比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於
+ U# |( u. S# k# m、小於。下面列出一些比较的pattern:
( u: W1 g! i7 N8 jx<y 如果 x 小於 y,则结果为真。! \$ J& Z, V* Y& Y) D
x<=y 如果 x 小於、等於 y,则结果为真。
* F" g- m$ o2 Ux>y 如果 x 大於 y,则结果为真。
. z U, g: l0 b" Z, O* q& q* Ex>=y 如果 x 大於、等於 y,则结果为真。$ c$ @; L2 X8 ~% R# F( @
x==y 如果 x 等於 y,则结果为真。
7 [( {+ J' Y' e- ~& zx!=y 如果 x 不等於 y,则结果为真。0 P5 O; ?2 o: @3 @# }1 V
x~y 如果 x 符合 regular expression y,则结果为真。
% l. q# m% j) ?- q7 ^' Mx!~y 如果 x 不符合 regular expression y,则结果为真。. @% Z% c% Y3 ?6 K+ G
上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,
. l4 X: [2 a6 w, I8 r否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,
1 J- A. ~/ K1 F' X# P' N5 |会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同) `8 S8 a( u! k/ f; P
的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视+ b9 d6 I+ _" p) _; m4 _
为长的字串比短的字串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。0 n, ~ m- Z3 S0 t
$ M9 Z: o! D' ?0 T ^ }, c
5.4 使用布林运算的Patterns
4 \5 t( F# G* R; F, [一个布林(boolean) pattern 是使用布林运算"或"('||'),"及"
$ o7 b4 l2 B' {1 T$ W('&&'),"反"('!')来组合其它的pattern。
! U. \% V6 m& Q& [+ X$ I例如:0 {- m: E. l# p! w: f) S4 X1 K
gawk '/2400/ && /foo/' BBS-list8 e' O0 n$ e8 V+ L. X* q% Z
gawk '/2400/ || /foo/' BBS-list
3 m! `0 H$ X) G; j' Z8 Z4 xgawk '! /foo/' BBS-list
9 e: q5 y' P$ A7 a; B! m/ ~/ d V, @3 ~$ r* x3 W! V% t! R
第六章 算式(Expression)作为Actions的叙述
3 L. k7 c; Q4 @算式(Expression) 是gawk程式里面action的基本构成者。
) J* a, ~ ~& `( B
& ~/ f% q" l* n) h6.1 算术运算/ O7 Q% X) a- }( X. u1 X
gawk 里的算术运算如下所示:
) S4 P; b* ^5 @; qx+y 加
: {4 e/ i9 P- W- y2 G: ?1 D) Lx-y 减/ N: M% y: q8 S9 X
-x 负
& a) g" E0 \) h/ ^+x 正。实际上没有任何影响。
8 H; |$ x9 \; q4 Q9 o' jx*y 乘) f) o- r4 |+ Y
x/y 除4 _# z+ d7 ?4 @% y5 T' B8 ?
x%y 求馀数。例如 5%3=2。
# N9 ~1 q! [9 L# Ix^y
* Y) F6 i# i3 C7 P7 j, ox**y x 的 y 次方。例如2^3=8。1 L, a! Z/ g9 i( |0 m/ T- ~! t" }
( @' }4 N( ]: l( |$ @: ?% e6.2 比较算式与布林算式
! N# F. }6 p, S5 U3 b8 a比较算式 (comparison expression) 用来比较字串或数字的关系
! ]' C* b" `/ N/ D,运算符号与 C 语言相同。表列如下:) |: u8 K; ?, l! U" I
x<y+ c) Y/ C b- B1 {. H/ S
x<=y
! k. y0 z; e" bx>y1 \% }3 X2 s- F
x>=y# C5 g6 y2 P" i
x==y
3 G' R# z# |, n0 z8 @x!=y
$ M9 N3 I# S' Q) f7 [x~y9 F1 b3 I3 d, W& u0 M: U6 ^
x!~y# K2 Y$ {' ^* M. V
比较的结果为真(true)则其值是 1。否则其值是 0。
/ w7 f- P0 V1 u布林算式(boolean expression)有下面三种:) Z; i. A3 m1 z" O
boolean1 && boolean20 {) ~ J3 u. E2 }) B
boolean1 || boolean2, J4 G y- O; V$ i
! boolean0 q( k: j4 g& f: Y# _: Q" K
' l+ S- G) I8 e9 e" P
6.3 条件算式(Conditional Expressions)
# ^) a9 D# ]% ^( o+ q# u+ K+ g+ G一个条件式算式是一种特别的算式,它含有3个运算元。
7 Q) M: I. n/ w条件式算式与C语言的相同:$ Z O8 }* k+ ^2 {* E3 C3 y b5 R/ X
selector ? if-true-exp : if-false-exp: ^1 Z$ e0 p0 o' E* {* U7 v, {
它有3个子算式。第一个子算式selector 首先会被计算。如果是真,
( y$ G7 Z; P+ {( \% N N+ b则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-+ e8 S, a! k% L; L8 _$ ]/ U- A
exp 会被计算且它的值变成整个算式的值。
- m: L" }: C5 ~. _5 Q2 p3 {' k例如下面的例子会产生x的绝对值:
7 X/ ]! C# A* Z1 f3 ex>0 ? x : -x
0 x: `% Z: h% u8 E) k
; K2 j" J3 b! B第七章 Actions里面的控制叙述) O; I m4 R6 h$ ]1 S' V3 T
在 gawk 程式里面,控制叙述诸如 if、while 等控制程式执行的流
$ L @9 K4 S( e8 V. V程。在 gawk 里的控制叙述与 C 的类似。
/ D& I( C3 G* h很多的控制叙述会包括其它的叙述,被包括的叙述称为 body。假 d3 Y6 F) j! |1 Q& b
如 body 里面包括一个以上的叙述,必须以大括弧 { } 将这些叙述括起6 q% j7 {/ [; D' V. N, M/ Z- @! _
来,而各个叙述之间需以换行(newline)或分号隔开。% j# v0 z: h+ ~$ a7 N
. ^$ [6 V3 p' F7 S, G' G, [7.1 if 叙述
g9 S9 ?4 r& F( V& x4 bif (condition) then-body [else else-body]( f( U" h4 S8 H% e) ~7 y' A O. y
如果 condition 为真(true),则执行 then-body,否则执行 else-body。8 O! D0 V7 Y! _3 n8 A- u7 o
举一个例子如下:
# p8 A2 s, d* M7 I9 iif (x % 2 == 0)
3 _3 |7 z5 d% _- ]4 t7 |2 G( d+ a4 \print "x is even"
9 t* R. s7 k, r) w7 r% Helse
$ J$ b' y( G. I: E* |4 d1 Wprint "x is odd"- S0 h6 w* L/ G
- o9 W4 Z, C# P ? e2 r* \# @5 U7.2 while 叙述$ x- \; b+ W7 ]( q7 A8 q. W" R2 j7 I
while (condition)
" Z' k& |- e" Y$ r+ B- U1 Bbody
+ ?& y! Y7 R, H1 W8 {( \) Gwhile 叙述做的第一件事就是测试 condition。假如 condition 为真则* g* m( ^- M* R$ X+ b- Y9 x
执行 body 的叙述。body 的叙述执行完後,会再测试 condition,假如; ?+ `, [6 v# j' _; o2 p
condition 为真,则 body 会再度被执行。这个过程会一直被重复直到
) W& x3 B5 h9 \' n6 E: m* xcondition 不再是真。如果 condition 第一次测试就是伪(false),则
: z0 [1 d; }# w+ N( S2 W$ Vbody 从没有被执行。7 ?& E3 S2 U4 E% V1 r- E
下面的例子会印出每个输入记录(record)的前三个栏位。
2 p) V5 k: O$ a4 i7 b ^, N4 a+ f5 kgawk '{ i=1' @ c- X+ W) X# r7 ?6 ?- y" J
while (i <= 3) {
0 X. ]. R7 n) a& [' uprint $i
# p! U4 N0 T- I8 ~, G4 P9 Pi++9 U9 h5 g9 f7 X/ K ]! h( B- U
}) `! W' b9 O& G$ y" P& V( `
}'
0 }' L# I* s8 o, o
' a8 O; A8 O" c" }2 j9 L# m7.3 do-while 叙述
" Q% {9 _0 x; J. I# E; f" }' Ydo9 Y! I# H. Z2 r& a
body8 Z9 X3 K, v: i
while (condition)
2 V. B0 c: `# m9 m这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。
9 l! ~, q* @* B+ v即使开始时 condition 是伪,body 也会被执行一次。
/ [- p' N) R& g6 `6 E下面的例子会印出每个输入记录十次。
( j' B2 T N% _2 t" vgawk '{ i= 1( b4 I* L! w. F7 i* Q. i
do {
9 X1 [2 T+ h/ H* ^5 {$ E* {print $0
0 l8 c6 j3 }5 q& m/ bi++
; t- X% X8 d" G4 V! F+ M W1 t7 `5 ^} while (i <= 10)
- p* g' s; r& M}': @3 O5 E0 e7 X2 S8 A X) V1 Z
7 q# u2 a6 [! x8 ?& m
7.4 for 叙述
& \6 S+ J5 h+ ]! S5 Zfor (initialization; condition; increment)
) M1 [6 r! I9 gbody' z- |: x2 r2 @0 x0 O
此叙述开始时会执行initialization,然後只要 condition是真,它3 `- W* |( D6 N
会重复执行body与做increment 。! `( i! w& C2 r1 y1 m. m
下面的例子会印出每个输入记录的前三个栏位。4 W6 h) L2 f+ m/ y0 s
gawk '{ for (i=1; i<=3; i++). b: J& U3 L* Z Y; Y0 e' T
print $i
9 U/ \; k. |( T5 b. `0 ]. K, X* K}'0 h5 T% ?" f4 g* e/ _
: A) [! E- s) X# h7.5 break 叙述' y# t. N0 }5 U! F
break 叙述会跳出包含它的 for、while、do-while 回圈的最内层。& z9 n. m8 ]. `. A6 B b
下面的例子会找出任何整数的最小除数,它也会判断是否为质数。5 _3 B* t* P3 [
gawk '# find smallest divisor of num
' J2 [" O% A8 E# t, ]& E6 z{ num=$16 `/ a# ~4 K: _. s8 ?+ F
for (div=2; div*div <=num; div++)
( } S. A9 h* l" r% r5 \if (num % div == 0)
& o9 h$ ?$ {; w& [break" ?- g6 l- }8 E% ]
if (num % div == 0)& n( i4 F; ^7 R8 ~, W( D- }
printf "Smallest divisor of %d is %d\n", num, div
- T1 K( E9 p/ Q% D, Qelse
5 I: T: f, t' G, s9 p/ ~printf "%d is prime\n", num }'
8 W- G- C, _% L
( E- W3 {( s# ]4 B' |- T$ O' E+ e7.6 continue 叙述
u0 t& s$ X9 s* S% _continue 叙述使用於 for、while、do-while 回圈内部,它会跳2 \7 m" ]4 \! P. c4 O* p8 n
过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。
! O4 T7 V* Y+ s9 }9 G' N# h下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。
- X2 U5 Y$ I7 s/ k9 zgawk 'BEGIN { ?- w) }8 t1 H3 y/ }2 i
for (x=0; x<=20; x++) {3 g. t+ B4 Z( \' k& p! N+ f
if (x==5)
' A2 g3 J4 ~( s3 n9 g9 fcontinue
5 [/ ^' X L8 l; }! M4 s5 Yprintf ("%d",x). g5 E0 e/ o2 a/ Y8 c& U6 z0 `
}
+ f; s" ~& \$ }8 f0 a! M4 Sprint "". y: ]+ J$ K4 b K# D
}'. Z% [7 C4 x; {7 N. J( ~* z
; L& |% h7 a& n8 u" a
7.7 next 叙述、next file 叙述、exit 叙述4 f x2 s. ^ m. T6 q) `' m& Y3 E
next 叙述强迫 gawk 立刻停止处理目前的记录(record)而继续下一
5 L5 Q& P& r2 Q& t- _6 ]! \, ~个记录。
: A" h. M# W2 s2 Z, Y4 E4 lnext file 叙述类似 next。然而,它强迫 gawk 立刻停止处理目前
/ e! m: l% Y# n" C的资料档。
_# t8 c4 Z4 [' ?0 c; n. Jexit 叙述会使得 gawk 程式停止执行而跳出。然而,如果 END 出现
& v# K B9 ?: n. I( U* t,它会去执行 END 的 actions。
+ h3 |7 [0 @! l. ^. f& D3 l7 f4 A1 i2 O! w( c
第八章 内建函式(Built-in Functions)
! l$ c3 m: j% m1 R' G- I' m内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建
R* m2 L' _! h+ y7 O6 x* e函式。" G: ?$ u" x* T# T1 p6 O
; h: R* T! f- F! C6 y
8.1 数值方面的内建函式
$ V' {, C+ w1 r5 N$ n% Uint(x) 求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9)
3 F: [! `6 `+ k! U% T6 E是 3,int(-3.9) 是 -3。
" W" {* o# a7 v# s a2 g" J$ o/ Wsqrt(x) 求出 x 正的平方根值。例 sqrt(4)=22 u" q0 C* R& ?9 a# g
exp(x) 求出 x 的次方。例 exp(2) 即是求 e*e 。; W: w+ f8 \( ^) a
log(x) 求出 x 的自然对数。( D/ l. P4 a& _1 N
sin(x) 求出 x 的 sine 值,x 是弪度量。! Z7 ], n9 i4 Y. P
cos(x) 求出 x 的 cosine 值,x 是弪度量。* V- [2 n; T n, \6 M0 F( H
atan2(y,x) 求 y/x 的 arctangent 值,所求出的值其单位是弪度量。4 l& B5 T8 b( v3 m+ I& c" U
rand() 得出一个乱数值。此乱数值平均分布在 0 和 1 之间。这个
( @) s3 T. T" u* }& t: N值不会是 0,也不会是 1。- W2 ~- e% L- {* Y8 d
每次执行 gawk,rand 开始产生数字从相同点或 seed。0 H+ e+ X" j A2 }
srand(x) 设定产生乱数的开始点或 seed 为 x。如果在第二次你设' C& L% ?* P! n: Y5 B. i5 X
定相同的 seed 值,你将再度得到相同序列的乱数值。
2 r. P+ }* X3 ]* X. t如果省略引数 x,例如 srand(),则现在的日期、时间会( p/ _. }9 ~) @2 G& Q
被当成 seed。这个方法可使得乱数值是真正不可预测的。
" {) L" t0 v3 w: S8 P7 gsrand 的传回值(return value)是前次所设定的 seed 值。4 N9 a) K& P: w% x/ w) X3 t; }. i
7 n( B& {) U0 l$ t& x+ \9 Y# ]
8.2 字串方面的内建函式
: s- l& Y) \! Eindex(in, find), t4 i1 k: s% J* P2 ?5 e( x/ Y4 v
它会在字串 in 里面,寻找字串 find 第一次出现的地方,传回值是! Z$ ?9 H; E' o0 I8 F [2 d
字串 find 出现在字串 in 里面的位置。如果在字串 in 里面找不到字1 ^5 F+ w, j) K: {. z8 ]8 p6 E$ \3 t
串 find,则传回值为 0。
5 U b* ^- B- t6 G/ [+ u/ f例如:
8 K( r9 s# m: G8 eprint index("peanut","an")& s# r, u. i) N! N7 j
会印出 3。
8 q* i+ {+ v+ blength(string)
7 E% a2 s0 Q& Q2 X/ Z$ a8 H ~求出 string 有几个字元。3 s- ?4 S4 e! x) s" x( N1 y
例如:
/ Y; P2 B8 M" P C) B* Llength("abcde")
2 u' U; N, U5 m( Z是 5。$ ~ W" F" d% i P Z- L
match(string,regexp)
+ U0 V8 ?, A: z; k* r& c, W5 N: qmatch 函式会在字串 string 里面,寻找符合 regexp 的最长、最靠3 K, l I6 \) k0 R6 I
左边的子字串。传回值是 regexp 在 string 的开始位置,即 index
: Z$ i& g, p0 D' H- Q: O值。" q* x) a% z& s
match 函式会设定内在变数 RSTART 等於 index,它也会设定内在变
3 |5 R% r' U/ [# ]5 s数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为3 Z/ Y) j6 k2 G( W w
0、RLENGTH 为 -1。! H; Y" M. V8 h4 Y+ e1 O( h
sprintf(format,expression1,...); Q9 w9 l. J0 S
举 printf 类似,但是 sprintf 并不印出,而是传回字串。
3 M" @' ?- L* p& b例如:/ `# o( |& d) P6 C4 m/ Y1 ]
sprintf("pi = %.2f (approx.)',22/7)- \. x/ U8 I6 }# C
传回的字串为"pi = 3.14 (approx.)". c7 o+ g ^. e1 q" o x" ?
sub(regexp, replacement,target)
; Z' M& G; I5 Q; ^7 X# C1 F在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,9 S: `# A- y! a3 l* k: ^! F4 w" v
以字串 replacement 代替最左边的 regexp。
! Z1 l" e# D& ^例如:
: G9 L% Q1 U) r1 ~$ kstr = "water, water, everywhere"0 S5 _( q2 ?* |4 V3 l5 A
sub(/at/, "ith",str)
% Q# m. K# Y3 k3 O! H/ H! W* E结果字串str会变成' m, t D0 ~. e" Y
"wither, water, everywhere"" A' C/ J6 Q) A1 r
gsub(regexp, replacement, target)
. Y; U9 F- K0 s! l' d- X0 o8 w1 Bgsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的
* U3 I: B1 y( S+ }8 u# b所有地方,以字串 replacement 代替所有的 regexp。
1 L3 |, ^! g8 `* u! M例如:, Y: ^0 B- `5 M/ H% O: ]7 f
str="water, water, everywhere"
2 u; `( l- J; z9 Sgsub(/at/, "ith",str)
. r- Q3 }5 p9 D+ e* E; e( G结果字串str会变成' Y" Q3 W2 n. n) X1 E2 ~) |2 r
'wither, wither, everywhere"
, v9 |, t0 R- e: t9 gsubstr(string, start, length)
$ y$ b E, i0 h2 E! q传回字串 string 的子字串,这个子字串的长度为 length 个字元,
{' v9 n; ^, i" J% {% x从第 start 个位置开始。
: W+ a- @! O; o8 K1 b例如:9 \( `8 ?0 S( m( z3 n, M4 B ^
substr("washington",5,3)* d* O$ r l& l0 U' Z0 d
传回值为"ing"# X5 l& ?# G0 K
如果 length 没有出现,则传回的子字串是从第 start 个位置开始
) k6 q, }+ @* t* H( x/ W& L至结束。- a$ F: i" _0 e5 N' y. c6 S$ z0 o) K' N
例如:
- C* V! a" ?. p) T* ]2 C# x! Esubstr("washington",5)
" e+ l' c; d4 F传回值为"ington"
% Y" r; b; }, e, P. `8 Gtolower(string)6 ?" r7 @. g: R3 p0 e) T
将字串string的大写字母改为小写字母。. h* E* y7 @; @
例如:. Y9 ]' q& i4 u
tolower("MiXeD cAsE 123")6 I: [& y+ j2 l
传回值为"mixed case 123"
7 p f2 q: Q2 b2 V7 \$ ^/ \toupper(string)
+ Z' s8 S( M E) e1 |5 R将字串string的小写字母改为大写字母。
8 m3 Q# B! E1 O$ \9 B/ h例如:$ B$ B9 [$ {7 A; K
toupper("MiXeD cAsE 123")" U& _( m7 h9 \3 q0 Z
传回值为"MIXED CASE 123"
+ X5 T3 I; g% G5 s6 P7 ^
* c- g" w/ ~# B2 ~; n3 Z; ^8.3 输入输出的内建函式
; w5 T; j! b5 qclose(filename); }1 N5 H% ]9 u) n) q5 k1 ]
将输入或输出的档案 filename 关闭。
2 n0 x' j( N3 E4 {9 r+ |" hsystem(command)
3 o9 q, y; T: y5 U, A此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk: Q* x3 R7 L" L2 f9 ~$ M
程式。) \0 n6 w$ z1 T1 S
例如:
- P2 \1 y2 f! g, o1 W3 A7 c# a+ gBEGIN {system("ls")}
2 j1 I2 V6 H' N1 p4 g- w
# m! }. @. ~- g" ^: K i第九章 使用者定义的函式(User-defined Functions)1 Y4 f* @5 V+ l0 r1 a' U
复杂的 gawk 程式常常可以使用自己定义的函式来简化。呼叫使用$ G6 Q" j. x) G5 w4 O" S1 x
者定义的函式与呼叫内建函式的方法一样。
$ D+ d! L3 _6 q1 H# ]0 i
k% o" k, G3 p( h; ?9.1 函式定义的格式, ~* i5 M: ]! B. @) z0 K0 n H
函式的定义可以放在 gawk 程式的任何地方。
0 J# C. L% z" M, h4 O( x一个使用者定义的函式其格式如下:4 Y* w1 U W4 S( K5 R- n
function name (parameter-list) {) @ F: z' w d! |
body-of-function( }/ U/ V1 N0 }5 q9 A; q
}
2 a" `3 r# w% Dname 是所定义的函式之名称。一个正确的函式名称可包括一序列的字
% U% l2 u# X0 ~$ e$ f: a母、数字、下标线 (underscores),但是不可用数字做开头。
5 v9 @% r7 Y3 h" I, v; Qparameter-list 是列出函式的全部引数(argument),各个引数之0 ~; `" L x$ z+ c
间以逗点隔开。
; B* }+ s# G7 E, h. o) ~) `1 Bbody-of-function 包含 gawk 的叙述 (statement)。它是函式定义 l7 Q+ s) f5 Y3 k# ~
里最重要的部份,它决定函式实际要做何种事。 L3 f8 n9 k: g. V
' f9 S3 z3 }0 B( U* Q! m8 _
9.2 函式定义的例子
2 G4 ~2 J' j( M% ^9 K; G下面这个例子,会将每个记录的第一个栏位之值的平方与第二个
0 ^5 H: u( D( r$ r栏位之值的平方加起来。5 w. C0 D9 @5 X6 A: U
{print "sum =",SquareSum($1,$2)}
) P9 O- v9 z( K3 n* t2 t% O6 Ufunction SquareSum(x,y) {4 E- ?; r: q- y, D9 t
sum=x*x+y*y& T7 K' P# H: f' J$ U
return sum, r8 g& Z( v; l4 k" _5 B
}5 L. G6 c) L6 {; _. Q0 S
' R5 o6 `; I- M2 X& l第十章 □例; d1 _, W* I+ H ] v" c4 E. ~( h
这里将列出 gawk 程式的一些例子。
" G( |, [6 X8 N( D/ X* B1 k) M: Xgawk '{if (NF > max) max = NF}; N9 {* ?, b- G3 C- a* K$ U
END {print max}'+ x7 [. `; T1 }) o6 b/ t7 U
此程式会印出所有输入行之中,栏位的最大个数。: Y" {; ]% V ]
gawk 'length($0) > 80'+ u; `0 P% Y9 d# F: _
此程式会印出一行超过 80 个字元的每一行。此处只有 pattern 被- a( M/ A0 g5 F# M- P* ^
列出,action 是采用内定的 print。3 q- @0 U: \$ @7 l
gawk 'NF > 0'
6 a& v6 K' i6 y) `7 j# S$ Q对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
4 S* N1 F0 |# R0 k; b1 N单的方法,将一个档案里的所有空白行删除。
3 O: E+ @8 k$ b6 Y \. Wgawk '{if (NF > 0) print}'
4 t% b W4 f4 |4 ?' `4 D/ W对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简6 n# ~: d: d6 G& L* S. Z" ~% N Y
单的方法,将一个档案里的所有空白行删除。 {- z& q2 f& S' X9 V5 z
gawk 'BEGIN {for (i = 1; i <= 7; i++)
# T# ~; S7 g, B3 w9 E$ \print int(101 * rand())}'
! ^: j7 H1 ]1 v( i7 q此程式会印出□围是 0 到 100 之间的 7 个乱数值。' s* `! ~1 H$ }
ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'; Q6 d& @5 `+ ?/ K' E
此程式会印出所有指定的档案之bytes数目的总和。
0 H. g9 D- k' l$ I# K! k! Dexpand file | gawk '{if (x < length()) x = length()} s" X* J5 ?9 T) N4 S) x8 V
END {print "maximum line length is " x}'
# E2 F3 y. b! N' P' e5 {此程式会将指定档案里最长一行的长度印出。expand 会将 tab 改
7 i0 Q) R: b1 S1 H9 q- V成 space,所以是用实际的右边界来做长度的比较。7 a/ D8 B* L' b) Q9 |
gawk 'BEGIN {FS = ":"}
5 A' s+ l% i! m* C7 L9 }{print $1 | "sort"}' /etc/passwd
7 Y% Q' E |1 h6 @% V5 K, x此程式会将所有使用者的login名称,依照字母的顺序印出。
" r; s& E7 t/ Z- d+ D" G+ bgawk '{nlines++}) `8 x5 @' f) j r; t3 D
END {print nlines}'
& H% P# X. k8 t: O此程式会将一个档案的总行数印出。) v+ a q9 G i0 ^; \, F
gawk 'END {print NR}'
8 y8 p8 c# j5 n0 x: ~此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk- h, G9 H; z1 V2 h/ a: |; t
来做。
. T5 v- \! Z3 a2 Pgawk '{print NR,$0}'- U* K& u# }2 i0 o; O' W/ k# e
此程式印出档案的内容时,会在每行的最前面印出行号,它的功
+ T+ {8 C# C, R能与 'cat -n' 类似。
9 [6 x s0 {% r
* j! L' L1 f3 O& t第十一章 结论
0 ]* d" n2 l [% F) k* igawk 对於资料的处理具有很强的功能。它能够以很短的程式完成
4 x. C3 p! W' X3 c想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件
% o/ o9 C5 X3 D, N# F工作,以 gawk 程式来写会比用其它程式语言来写短很多。
: I, P8 a" ^: |gawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使. U" p" ?( K) ? N
用。 |
|