TA的每日心情 | 奋斗 2019-2-12 09:32 |
|---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到 累计签到:1 天 连续签到:1 天
|
|
马上加入,结交更多好友,共享更多资料,让你轻松玩转电力研学社区!
您需要 登录 才可以下载或查看,没有账号?立即加入
×
GAWK2 c) j6 U4 C* A
第一章 前言; _2 b9 V) r/ t. {' P, h* p; G
第二章 简介
9 x5 }7 s7 O* P! e0 j第三章 读取输入档案- H( b+ g( B2 W* Z
第四章 印出+ H- N) K( i2 f8 F8 q
第五章 Patterns) l3 B# @9 V: h6 O' \3 \: v
第六章 算式(Expression)作为Actions的叙述4 X6 ^5 P+ ?& ?8 h0 p5 y: I- y- L
第七章 Actions里面的控制叙述
* q0 ^8 L, d2 x第八章 内建函式(Built-in Functions)) k Y" p6 ?2 z. V( ^7 s7 ?! B6 Q
第九章 使用者定义的函式
2 U& u9 M2 F4 Q/ P( [; `第十章 □例$ h9 i; |' p9 J O6 k: @7 ]1 s* `- P) G
第十一章 结论
2 \, R3 e$ v f+ ]1 p) c9 ^% X {' ?- y
=======================================1 e: n- }: i v3 `% O
第一章 前言4 J9 z& n2 K* T) {7 c' y
awk 是一个程式语言,对於资料的处理具有很强的功能。对於文# k( f. p% u& O# L% [
字档里的资料做修改、比对、抽取等的处理,awk 能够以很短的程式
" b9 |5 A* B+ Y5 t* Z' _* e5 W轻易地完成。如果使用 C 或 Pascal 等语言写程式完成上述的动作,* j$ q6 w8 z0 Y, U+ S& P
会不方便且很花费时间,所写的程式也会很大。2 @# c" }( x2 H5 j- N
awk 能够依照使用者的定义格式来分解输入资料,也可依照使用( q2 @4 D& N8 d
者定义的格式来印出资料。, v, Q, T W3 \! ?
awk 名称的由来是由它的原始设计者的姓氏之第一个字母而命名
' y1 Q6 ^" y0 S" D:Alfred V. Aho, Peter J. Weinberger, Brian W. Kernighan。2 y# T7 P: J" O# @4 M- \+ {) _
awk最初在1977年完成。一个新版本的awk在1985年被发表,它的功能
( N$ m3 j0 M/ K7 U2 i2 A- Y- G比旧版本增强不少。
1 V7 o* F- b5 Q+ l d# ]gawk 是GNU所做的 awk,gawk 最初在1986年完成,之後不断地
; T4 d4 j7 n& R! [; p! G被改进、更新。gawk 包含 awk 的所有功能。# P$ i% w% k( V D) Z$ C1 F+ R& z% I
往後的 gawk 将以下面的2个输入档案来做例子说明。
# N. V/ @# g8 L3 q9 ~6 H4 w档案'BBS-list':" I6 z/ A% f3 F6 d" }8 O. B7 k
aardvark 555-5553 1200/300 B) w5 P1 m0 [) w2 y% n
alpo-net 555-3412 2400/1200/300 A
+ J) ]( b7 Q1 a5 Q. b4 i4 d, Cbarfly 555-7685 1200/300 A" O* y7 e0 z* \- \
bites 555-1675 2400/1200/300 A# C: q0 ? ^9 g! Z' T+ x
camelot 555-0542 300 C
9 Z2 v, a3 c3 O4 Kcore 555-2912 1200/300 C4 I9 l. N P9 q+ p$ k! S5 h2 l: j
fooey 555-1234 2400/1200/300 B
1 a2 C- e- @8 k8 X5 efoot 555-6699 1200/300 B. B; I2 ?& A9 z, A$ B% e1 t# ~& s" i
macfoo 555-6480 1200/300 A+ v& X* T( ]5 b( u
sdace 555-3430 2400/1200/300 A, i4 ~0 e2 v2 V- I1 X+ M
sabafoo 555-2127 1200/300 C$ l6 S1 K7 P' z
档案'shipped':; _% D4 @4 Z/ d) ?8 @- p
Jan 13 25 15 115
% p; x" J7 Y, j5 nFeb 15 32 24 226) Q( Y c, C8 y( x' U2 p
Mar 15 24 34 228
' ]5 M# M! P) R# D' s4 z. tApr 31 52 63 420+ o, q8 c5 g5 B) U! i2 ~
May 16 34 29 208
1 }3 V, a2 [' G& X6 R- EJun 31 42 75 492
, K w5 Y/ f' YJul 24 34 67 4361 w; Z6 l* O8 L: |
Aug 15 34 47 3167 c1 ]! a2 w, r0 |9 i
Sep 13 55 37 277+ z2 B3 d8 _+ z ]; |' b
Oct 29 54 68 525
U( L5 C2 x0 i+ q N2 p! BNov 20 87 82 577
4 l: X. R! ]- V2 u8 R0 xDec 17 35 61 401
9 k; T7 i2 i( G2 [* uJan 21 36 64 620
O* r6 j) e' A0 @$ |1 BFeb 26 58 80 652& s! S* l3 ^5 N6 i
Mar 24 75 70 495
' g# X2 B8 X+ CApr 21 70 74 514
' d0 ]! ^* C" z
; z9 P2 ? q! n- m9 G第二章 简介
& t4 _* `8 ?) K4 K7 i* W8 `9 lgawk 的主要功能是针对档案的每一行(line)搜寻指定的 patterns: I9 `- I, T+ x2 O6 D8 m! J9 K
。当一行里有符合指定的 patterns,gawk 就会在此一行执行被指定
/ j5 w5 _9 H+ @4 f$ O3 O" a; x的 actions。 gawk 依此方式处理输入档案的每一行直到输入档案结
4 Q2 ^7 r7 Q f! `: t$ i4 `束。* m5 _4 R! C* z- N t- `
gawk 程式是由很多的 pattern 与 action 所组成,action 写在* R Y# d% i, }/ B, g7 U# v u
大括号 { } 里面,一个pattern後面就跟著一个action。整个 gawk 程# F, h% T, j) s+ X& z
式会像下面的样子:
, f; Y. C& n$ \3 I: ^/ k; apattern {action}
3 L' t5 V. P# p( G' M* `$ \+ dpattern {action}. E0 V8 \5 p- z# n1 p* I6 n$ H
在 gawk 程式里面的规则,pattern 或 action 能够被省略,但7 N. A' I8 a3 b3 d. k# L2 J- D; F: f3 T
是两个不能同时被省略。如果 pattern 被省略,对於输入档里面的
' F) b2 j. {+ ]8 S每一行,action 都会被执行。如果 action 被省略,内定的 action9 {: D' B6 t' A! C
则会印出所有符合 pattern 的输入行。% O1 F7 a# B7 ^# v, [$ }( o0 b+ @
7 h. M4 W2 {. i ~" [0 v- |2.1 如何执行gawk程式
0 s1 b, @6 A) T7 r9 m5 p; `基本上,有2个方法可以执行gawk程式。0 Z/ p- j' e3 w/ O2 `! M
□如果 gawk 程式很短,则 gawk 可以直接写在 command line,如下所示:
1 W9 }5 g5 j8 N9 r6 bgawk 'program' input-file1 input-file2 ...
6 |7 n5 B$ E- Y3 e( [其中 program 包括一些 pattern 和 action。2 W) { U5 ~$ N, u f0 y d
□如果 gawk 程式较长,较为方便的做法是将 gawk 程式存在一个档案,
2 H* }2 k6 I1 i即 patterns 与 actions 写在档名为 program-file 的档案里面,执行: X. c; c- `5 j" A3 |
gawk 的格式如下所示:
5 s* g# e1 I' u H" rgawk -f program-file input-file1 input-file2 .... b# e& N' }, D: R \# ~+ P- {* [
gawk 程式的档案不止一个时,执行gawk 的格式如下所示:
2 w2 ?/ l; @0 R5 Z/ |7 m wgawk -f program-file1 -f program-file2 ... input-file1
# K5 j1 d2 k- l4 Qinput-file2 ...% Y6 m) v7 N3 I; S0 ^% e
p( a! A7 ]4 C2.2 一个简单的例子
" I7 {" C1 }& E. Z' U: F现在我们举一个简单的例子,因为 gawk 程式很短,所以将 gawk 程
( X) G; k* Y l3 e4 _式直接写在 command line。
' I7 z9 p) v& ]& G/ N/ A! Ggawk '/foo/ {print $0}' BBS-list
# h' w6 e7 Y* s% r9 D实际的 gawk 程式为 /foo/ {print $0}。/foo/ 为 pattern,意思为搜
' y/ j1 d. U' V+ C$ T寻输入档里的每一行是否含有子字串 'foo',如果含有 'foo' 则执行 action。
, E4 V- {+ V6 n" G/ maction 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。
" D+ [; ~3 _. F2 y1 K& o执行完上述指令後,会印出下面的结果:
" f* c" w3 d Ffooey 555-1234 2400/1200/300 B
* O+ t8 p3 E! h _3 yfoot 555-6699 1200/300 B0 u. t$ x, J0 M, v. ^' r f
macfoo 555-6480 1200/300 A
5 J$ \% |4 K. S9 {0 Q% M' lsabafoo 555-2127 1200/300 C
/ w& w) f& L) r: @
& O) p! a$ X$ Z2 h5 D5 ^2.3 一个较复杂的例子" e2 @; x1 g* E8 T% T- \
gawk '$1 == "Feb" {sum=$2+$3} END {print sum}' shipped
( {1 Q7 C3 d4 r2 k' G# p现在这个例子会将输入档 'shipped' 的第一个栏位与 "Feb" 做比较1 @% B* H0 l% m Z' u
,如果相等,则其对应的第2栏位与第3栏位的值会被加到变数 sum。2 R+ {. f$ f7 A* `
对於输入档的每一行重复上述的动作,直到输入档的每一行都被处理" M+ {% A' T( Y& r! d2 O6 ]
过为止。最後将 sum 的值印出。END {print sum} 的意思为在所有的输
4 L: l! Q4 a( V. q# a9 \# p入读完之後,执行一次 print sum 的动作,也就是把 sum 的值印出。
% y, q! ~$ ^! L! F下面是执行的结果:& N' A* R4 t: Y: a9 E" Y
84
* \7 f. H" H/ T5 E" j$ O4 O I! I, ^# W2 ]' c
第三章 读取输入档案
. h1 ^! g% U* X" mgawk的输入可以从标准输入或指定的档案里读取。输入的读取单/ H( ~2 Z5 y; C
位被称为”记录”(records),gawk 在做处理时,是一个记录一个记2 l2 Y& L+ H3 _! I* F2 I
录地处理。每个记录的内定值是一行(line),一个记录又被分为多个) O3 D7 x: ^+ x4 m; V9 a8 {! S+ t; ^
栏位(fields)。
: n7 q& c; B1 x1 w* z: |' ?5 V3 z% E
3.1 如何将输入分解成记录(records)0 T/ U t# N" M
gawk 语言会把输入分解成记录(record)。记录与记录之间是以
( ?( _, ]# V# H) Srecord separator 隔开,record separator 的内定值是表示新一行的* e, t H: w c
字元(newline character),因此内定的 record separator 使得文字
+ M1 W1 o% C9 ?1 p的每一行是一个记录。; E" n8 ^9 |0 H, F
record separator 随著内建变数 RS 的改变而改变。RS 是一个字串,+ q U/ ]6 B6 u% F1 t
它的内定值是"\n"。仅有 RS 的第一个字元是有效的,它被当作 record
( H2 `5 T. Z! i0 l) {+ o' a6 Q& p0 [separator,而 RS 的其它字元会被忽略。/ A+ ~* {6 T1 @- r3 W' M) u; F" l
内建变数 FNR 会储存目前的输入档案已经被读取的记录之个数。内
8 J0 C3 Q- C5 g3 i9 d建变数 NR 会储存目前为止所有的输入档案已经被读取的记录之个数。
0 ?& }8 A W j2 j) J( |7 G0 d* W6 W( v/ v) i
3.2 栏位(field)9 p& G. k9 I9 Q
gawk 会自动将每个记录分解成多个栏位 (field)。类似於字在一2 q& G5 z3 p8 w# x: S' {! N& X- L
行里面,gawk 的内定动作会认为栏位之间是以 whitespace 分开。在; o6 z, j+ k5 W W( z+ s5 Z9 x9 T C
gawk 里,whitespace 的意思是一个或多个空白或 tabs。! U) Y( f) W) C" b
在 gawk 程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位" s' r& ?, y$ \1 {& `
,依此类推。举个例子,假设输入的一行如下所示:
* {7 ^9 ?+ K% a% g0 ~9 v. J! [This seems like a pretty nice example.) \5 s* Y3 A' s2 L% D. }3 \. e3 G
第一个栏位或 $1 是'This',第二个栏位或 $2 是 'seems',依此类推。' J9 }- s. F* W% w$ R6 ?
有个地方值得特别注意,第七个栏位或 $7 是'example.'而非'example'。
. ?* g0 S1 ]8 |1 E不论有多少栏位,$NF 可用来表示一个记录的最後一个栏位。以; r/ E/ V4 Q$ V) y
上面的例子为例,$NF 与 $7 相同,也就是'example.'。
9 L9 i0 B& ^/ E* F% o: w0 o) gNF 是一个内建变数,它的值表示目前这个记录之栏位的个数。
3 w$ u! p# M. F5 |. ~, F% X8 Y" P$0,看起来好像是第零个栏位,它是一个特例,它表示整个记录。5 p, A3 M5 O( |% v2 h2 m+ a7 E
下面是一个较复杂的例子:# ~% c Z5 g3 b+ y% s2 C
gawk '$1~/foo/ {print $0}' BBS-list. e4 r( ^1 V0 |5 [$ j s7 [: x
结果如下:7 E( z0 w3 v$ |1 [8 c- I) N5 n* H I
fooey 555-1234 2400/1200/300 B$ Y4 d' b% J: g4 H; s
foot 555-6699 1200/300 B0 K/ ?2 V- v8 l N3 j' n2 u
macfoo 555-6480 1200/300 A% f# C, Y. }; R& v! [
sabafoo 555-2127 1200/300 C+ j0 ]" [% U7 P& t
这个例子是把输入档'BBS-list'的每个记录的第一个栏位作检查,如
4 ]. `' A3 W& i5 t0 c果它含有子字串'foo',则这一个记录会被印出。
" I9 W; s1 G9 B: J0 ~, N' p9 ~5 z3 c
# y8 I$ d7 _5 p8 z) C; n0 D0 Z3.3 如何将记录分解成栏位4 }3 [- k' g8 y& Z9 |
gawk 根据 field separator 将一个记录分解成栏位。field sepa-* P5 E5 ~6 M( ]
rator 以内建变数 FS 表示。
5 k' m5 `* [+ }' l举个例子,假如 field separator 是'oo',则下面的行:
. T- a3 @- _6 ^moo goo gai pan
+ j0 T& g) r. G' H6 l会被分成三个栏位:'m'、' g'、' gai pan'。
I% i b: D& }- @在 gawk 程式里,可以使用'='来改变 FS 的值。例如:
1 _9 m' k4 v% }+ l4 h$ \0 egawk 'BEGIN {FS=","}; {print $2}'
& p3 Z& y# p5 G7 p, a) V+ p, a输入行如下:
7 g) o. b! \5 h& @& O, RJohn Q. Smith, 29 Oak St., Walamazoo, MI 421395 L2 ~3 J! e& g' A) h7 v
执行gawk的结果将印出字串 ' 29 Oak St.'。BEGIN 後面的 action 会在
0 |5 H3 R4 u: ~. H/ A& K/ a第一个记录被读取之前执行一次。
% S2 |" w4 ?& f1 H! Q
( t% ~- L% f9 w, w' H8 }8 I第四章 印出
% B7 j4 N6 w. ^/ A' z/ x在gawk程式里,actions 最常做的事就是印出(printing)。简单
6 f J7 z2 i$ w6 Q& ?的印出,使用 printe叙述。复杂格式的印出,使用 printf 叙述。" O, p- N& ~& e& e
* V7 U5 G e9 S9 ]$ I( p6 T: Z4.1 print叙述 j" m: \5 N! ]1 a3 i
print 叙述用在简单、标准的输出格式。叙述的格式如下所示:9 z7 Q7 K* q5 d1 K1 r S
print item1, item2, ...
3 B$ T- h6 j* Z+ D: [0 g/ L7 s输出时,各个 item 之间会以一个空白分开,最後会换行(newline)。0 P- ]8 R9 b* d, Y; N# `; F% F% U& I
如果 'print'叙述之後没有跟著任何东西,它与'print $0'的效
# f w. g4 c# R, v# r2 ^# e果一样,它会印出现在的记录(record)。要印出空白行可使用'print
3 j6 m& T' D/ P% t$ V""'。 印出一段固定的文字,可用双引号将文字的两边括起来,例如
8 u, ~3 ]6 s/ ~. }'print "Hello there"'。
m( d! w+ Q& p; s- q; c这里是一个例子,它会把每个输入记录的前二个栏位印出:
1 r( L6 ]$ d0 _0 E, m0 Q2 Tgawk '{print $1,$2}' shipped, f' T. S8 h- q3 _% x+ m2 K1 ]+ K
结果如下所示:
6 |0 Q- P& e, N( [ i! jJan 136 `, n! ?4 t* d6 W& t r1 r6 A
Feb 15
5 F# }4 ^- K8 w: t1 b- N& @/ O/ JMar 15
1 }) v! y) L$ Q; ~) E$ xApr 31
0 _# _1 L) B6 B/ o8 _May 16
7 v: ?# p; [2 `: P* H: D GJun 31
0 r5 y7 G7 ]. l- SJul 24
9 j3 y3 q; s* x' d! a HAug 155 o* D" Z6 |' E) f* z: o
Sep 13
' Y2 L: @* ?; x, G- X" iOct 29
5 }3 Q- k5 C) _9 w! ~; B* uNov 209 c/ _% p. n3 i, B6 D
Dec 17
( `7 f0 D, P b+ D, iJan 218 O' L2 Y( L/ d# Q* {. n: h; {2 o
Feb 26
5 c5 ?) ?/ ~7 x) xMar 24
5 ]5 C! r: D! U0 |3 `Apr 21
8 K# S8 \, _4 w! s5 F
5 L! \' ]! d1 u7 x4.2 Output Separators! C7 S' ~) L9 d
前面我们已提过如果 print 叙述包含有多个 item,item 之间
}" U, d9 c L- [ j4 h# k2 B用逗点分开,则印出时各个item会被一个空白隔开。你能够使用任何1 Z: j5 Z5 X$ B% P4 y; S. b$ i5 `
的字串作为 output field separator,可以经由内建变数 OFS 的设8 c7 ~ \2 Z7 C) z+ ^9 A
定来更改 output field separator。OFS 的初始值为" ",即一格的
+ `9 G: v9 p# e" h2 Z. ]空白。" N! x) Y( v5 e# V+ |
整个 print 叙述的输出被称为 output record。print 叙述输
1 e3 `* V7 [# g+ \% b出 output record 之後,会接著输出一个字串,此字串称为 output
: U& c, W2 s& l$ Krecord separator。内建变数 ORS 用来指明此字串。ORS 的初始值
( V! ?/ |) E- m$ }* M# J( C; ~为 "\n",也就是换行。
9 z" \' h+ t( u下面这个例子会印出每个记录的第一个栏位和第二个栏位,此二6 B" O. u- K( W1 O ^8 s
个栏位之间以分号';'分开,每行输出之後会加入一个空白行。" M6 y* \! e9 F
gawk 'BEGIN {OFS=";"; ORS="\n\n"} {print $1, $2}' BBS-list- ^+ E# P7 Q5 P) U$ H/ ~4 z9 k
结果如下所示:
' N8 Z5 n/ S7 d3 A) j; Waardvark;555-55530 `0 y( g% J% B2 r+ B
alpo-net;555-34128 p: W: R" X: L
barfly;555-76856 O0 O9 \( D7 Z0 y
bites;555-1675
5 U0 a! |2 `" J0 U/ t; Wcamelot;555-0542
* _+ o# j' j* icore;555-29120 Z4 P! E$ p Y: N- b
fooey;555-1234$ q# k' U& X# `% b2 `. Y( Q3 {( S
foot;555-6699
4 Y! F7 S3 {/ [2 U. R7 w* Emacfoo;555-6480
4 }: \/ E' Q3 w$ O0 T) `) gsdace;555-3430
! N3 D# U; u ?sabafoo;555-21271 e; p8 L8 h2 Y& x1 D- C' Q
8 W ?6 @& j" e9 h0 W& V$ y4.3 printf叙述
5 B: k8 ^. q! h: ?: Pprintf 叙述会使得输出格式较容易精确地控制。printf 叙述可以
8 h- e7 v- O1 ^+ Z: w指定每个 item 印出的宽度,也可以指定数字的各种型式。
1 h* b+ |! `1 b0 V- R" nprintf 叙述的格式如下:
3 q) J6 U% ^$ ~2 j" Qprintf format, item1, item2, ...
; d# n3 Q Y# Z5 Fprint 与 printf 的差别是在於 format, printf 的引数比 print
9 D% V9 \- l+ q& U多了字串 format。format 的型式与 ANSI C 的 printf 之格式相同。
% o3 _+ E% O2 s3 @6 oprintf 并不会做自动换行的动作。内建变数 OFS 与 ORS 对 printf 叙' Y8 d& [4 I2 S# t" M5 h
述没有任何影响。
, e# q2 a& T; a, s Y% i% S0 X格式的指定以字元'%'开始,後面接著格式控制字母。7 u' N" f$ a3 u9 \- {7 x9 g7 b6 v
格式控制字母如下所示:
& a/ r, [* k6 ^+ v3 @5 }) I. B'c' 将数字以 ASCII 字元印出。3 e9 S' x2 k- M9 [& z
例如'printf "%C",65'会印出字元'A'。
+ {/ L- b/ @2 E! A, P4 o'd' 印出十进位的整数。
9 o" H, E+ K% y'i' 印出十进位的整数。
- q2 r) b# @# R'e' 将数字以科学符号的形式印出。" b9 i5 s! I4 a* q& w, G
例如; H% W; b& I$ q8 A' B4 V; [, V/ E
print "$4.3e",19508 C' y" N8 D& _% z$ t. ~
结果会印出'1.950e+03'。 H( U8 D1 S7 P( w$ p z) o7 V
'f' 将数字以浮点的形式印出。
) f7 K- _! t( _! a: L'g' 将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果
1 ^& W. t) x+ M4 w+ Y0 S大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印
, `" \9 w' Q5 _4 }9 c3 o' \, @$ s5 u5 V出。
0 O; j0 v: R! e* k7 B/ I; s i" G'o' 印出无号的八进位整数。
5 A$ f& \2 a& i's' 印出一个字串。
, [1 V7 D. F! t* l& \: Q'x' 印出无号的十六进位整数。10至15以'a'至'f'表示。! }% o' d( T# O# g* W4 U
'X' 印出无号的十六进位整数。10至15以'A'至'F"表示。 K) _7 ^' t: I& O6 |6 b% ~ F* E
'%' 它并不是真正的格式控制字母,'%%"将印出"%'。" p- H9 U0 `3 X: T) R1 ?1 d
在 % 与格式控制字母之间可加入 modifier,modifier 是用来进一: Y6 S8 }$ H( T- J7 V- c2 {
步控制输出的格式。可能的 modifier 如下所示:
2 `& Y/ J8 }( {* z4 g' o9 g'-' 使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在
, S( h7 c' W- n3 L5 y) D0 F被指定的宽度向右靠齐。例如:, c( u" K6 R2 Y- h$ y
printf "%-4S", "foo"
9 M5 N+ z. b7 J/ n) g8 h) m# t会印出'foo '。: R' R0 E' D- u `: o5 z
'width' 这一个数字指示相对应的栏位印出时的宽度。例如:
: |, n& y$ D. A# D4 g! y/ vprintf "%4s","foo" G- ^6 O6 r* u2 H- C7 m4 C
会印出' foo'。4 y U& y; B4 b$ A! N9 K$ M
width 的值是一个最小宽度而非最大宽度。如果一个 item 的( f, l& y: D# {& b( s* j, u, o
值需要的宽度比 width 大,则不受 width 的影响。例如
+ |% f( v" S+ r9 d! |( }" j- m& L$ Iprintf "%4s","foobar"
" B# D$ ~. [, P- L0 [2 m将印出'foobar'。
! U' a9 k% t4 `8 \! H% u$ L'.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。如
& E+ g/ l6 g+ V& \/ }1 A( N果是要印出一个字串,它指定此字串最多会被印出多少个字
" J4 e5 ]- v$ Q; y元。8 T U- @7 U7 X9 t. [) r( d
8 L6 f2 x5 Z/ s( g
第五章 patterns1 _; |- V& r& j% D
在 gawk 程式里面,当 pattern 符合现在的输入记录(record),其1 F5 u! d2 |- R5 C: C
相对应的 action 才会被执行。7 i" M' e& v4 ?/ \ v" y
( E2 Y! Q# A7 R" Y5.1 Pattern的种类
# o! q7 o- r5 m- o/ d1 F这里对 gawk 的各种 pattern 型式作一整理:
" X" j4 z; P1 m' @/regular expression/6 @0 p5 k; {5 \! N: Q
一个 regular expression 当作一个 pattern。每当输入记录 (
7 n2 D% D. S% f3 ]* Irecord)含有 regular expression 就视为符合。# a8 Y/ F7 d0 P- E5 N: @& e
expression
6 z/ X+ y- E* V4 r一个单一的 expression。当一个值不为 0 或一个字串不是空的," |4 G; x6 o* ]+ ~( M
则可视为符合。( w! r, P" H. r0 f" B* j
pat1,pat2
0 c9 s/ e" @7 Y! L! c, V一对的 patterns 以逗号分开,指定记录的□围。! C8 }0 d9 X. O5 e+ C
BEGIN
/ U# P6 N6 \5 j3 a( E; }3 o$ VEND, ?5 r- }9 q' ~- ~% l: S
这是特别的 pattern, gawk 在开始执行或要结束时会分别执行相
, L, m. c# f' A+ M$ I. B) }) Y对应於BEGIN或END的 action。! s& D1 }" s2 K5 ]/ S
null
$ `8 ]9 t0 q% e8 M; c2 H/ R5 p这是一个空的pattern,对於每个输入记录皆视为符合pattern。
: {8 C, R2 Q( I7 Y `
# q2 u/ Z+ I' G [5.2 Regular Expressions当作Patterns
; {5 ]2 t* E! x. q1 @) ]: q一个 regular expression 可简写为 regexp,是一种描述字串的方4 h" J7 I! n/ E
法。一个 regular expression 以斜线('/')包围当作 gawk 的 pattern。
7 m2 P* [) U& F- W$ l) G) B% j9 B如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,; q% ]; u9 x7 i; b+ o0 ^
对於任何输入记录含有'foo'则视为符合。4 e5 }" l0 l0 `4 J% \! `* S6 N
下面的例子会将含有'foo'的输入记录之第2个栏位印出。
& E/ V. M |9 c2 d0 P) s+ agawk '/foo/ {print $2}' BBS-list
/ g: x5 ~# V, n$ ~# [: ?3 X结果如下:3 ]; W# m6 t/ Y* H
555-12348 F: v. U1 u, s& Q% H) H. ]
555-6699
3 g- I* ^! k( E5 b9 z5 J K555-6480
9 j. v5 B: x6 c8 ^+ |555-2127
: v" z( k7 h' Aregexp 也能使用在比较的算式。5 |$ m! q! S6 E" x
exp ~ /regexp/4 W0 \" Z" x& E, O2 y
如果 exp 符合 regexp,则结果为真(true)。
# N8 p% m. ?! f- E3 r$ zexp !~ /regexp/0 U6 k/ E5 n, {) w' X
如果 exp 不符合 regexp,则结果为真。
& E z. Z$ {) z1 G. f
& y0 i0 |1 b: _- A5.3 比较的算式当作Patterns
! A; F5 c J# f% d3 t+ X0 q比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於
4 a n' M7 b7 ]$ F5 b、小於。下面列出一些比较的pattern:
' I3 W4 t+ H3 O/ D9 ix<y 如果 x 小於 y,则结果为真。% }$ E; O" S6 ]+ _% c
x<=y 如果 x 小於、等於 y,则结果为真。
6 r; C: O1 |! j# Y+ l, gx>y 如果 x 大於 y,则结果为真。4 [! G( ^0 r% _6 G$ p
x>=y 如果 x 大於、等於 y,则结果为真。
1 b, T( S8 J, U, E/ e) j6 A: kx==y 如果 x 等於 y,则结果为真。
' n* {# M$ g6 Dx!=y 如果 x 不等於 y,则结果为真。& A: Q! j( p5 X
x~y 如果 x 符合 regular expression y,则结果为真。+ k8 ^! B8 F/ V8 S1 `7 L
x!~y 如果 x 不符合 regular expression y,则结果为真。
9 O/ {4 K8 c8 Z6 M( `上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,5 Z# k& M6 s& ], j& e
否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,& U) i- n% A- V. a
会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同
* t3 M( S) B$ d; N2 u" _的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视+ d W. |* Z, c( O8 `0 l2 @
为长的字串比短的字串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。
1 Y- z3 F0 P$ U) V* g0 f& e/ R# ?& N; o$ [* m
5.4 使用布林运算的Patterns- D, j8 Y" W( d' Z6 M7 T
一个布林(boolean) pattern 是使用布林运算"或"('||'),"及"& w1 S7 z3 C0 u3 |$ ]
('&&'),"反"('!')来组合其它的pattern。8 m. O5 y# h- c
例如:" Q' D: d! r H& ^) _4 ]# B
gawk '/2400/ && /foo/' BBS-list! y$ I2 D( O5 H: F8 R( U" M
gawk '/2400/ || /foo/' BBS-list7 ~+ u* B ]% r. m- q
gawk '! /foo/' BBS-list
! p" V* \1 Z7 b+ |
/ p4 V1 p8 i) _5 F第六章 算式(Expression)作为Actions的叙述% u1 k% [0 M6 ]% m+ _( _) N" M
算式(Expression) 是gawk程式里面action的基本构成者。
6 I& A; g( ]% M2 g" u6 n
' Q. O, d1 g+ P2 ^; q6.1 算术运算: [5 d B# f4 V) @1 [7 B; E( j
gawk 里的算术运算如下所示:- l" J$ d9 c. u1 A2 u0 Y2 J; \
x+y 加
6 n6 C+ T5 e0 G- Gx-y 减
( e1 b- z- d9 z0 ]-x 负
5 v: x; j4 k! |2 O+x 正。实际上没有任何影响。. s* {- H* e7 C8 ^
x*y 乘4 E1 _1 l8 S8 x
x/y 除( ]! s# ~' W0 a) ~; l
x%y 求馀数。例如 5%3=2。
) W' V$ s4 N* R# Vx^y
' \. E- ^$ [3 C$ n( ix**y x 的 y 次方。例如2^3=8。% ?' T/ o9 r. a8 } H1 t0 f! {5 _
% D7 y( V U) A5 y6.2 比较算式与布林算式
4 X' e3 ~! b" i" t9 k9 {/ O比较算式 (comparison expression) 用来比较字串或数字的关系
+ b% V. S) a$ d' B$ S0 V,运算符号与 C 语言相同。表列如下:
& j2 T# |3 F7 p0 a$ mx<y7 z# v7 `0 R! b1 R. D* b
x<=y
# V- Q5 X" ]+ X+ i! F$ ?* v. {x>y9 s" @1 `& G( k& h! X2 m. ~9 ]
x>=y
& S; ?; M3 Z% ~0 { r( [. }+ rx==y
5 @4 Q b: }1 \x!=y
) `4 [2 v9 E1 x& w1 Nx~y
7 Y1 k$ p, i& Y6 E1 |( Zx!~y! ^- x2 H" ~% M6 c( g
比较的结果为真(true)则其值是 1。否则其值是 0。
" H5 U$ p! ?' {2 T* _" p布林算式(boolean expression)有下面三种:
0 z Z$ R: c# H, cboolean1 && boolean2
) G" g, g& u; g6 j6 U8 B# u$ Hboolean1 || boolean2! z1 x+ _7 ] ?$ V5 W
! boolean
. |: k# a3 j( L3 D% _* r$ K3 G3 \- b; G) x7 t
6.3 条件算式(Conditional Expressions)& y2 M# P$ ]1 U9 `# h6 s
一个条件式算式是一种特别的算式,它含有3个运算元。, t( e( _& S! ^% m
条件式算式与C语言的相同:, _( v6 p+ c, J
selector ? if-true-exp : if-false-exp# N, v) s6 ` e5 Z3 ]% ]5 c
它有3个子算式。第一个子算式selector 首先会被计算。如果是真,/ {; S( ]5 t% B5 s9 w; t( j6 ~) U, q' L
则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-7 T/ I6 [0 a' g) P) u4 v
exp 会被计算且它的值变成整个算式的值。3 n3 i7 X7 v! o' I$ A6 t8 N
例如下面的例子会产生x的绝对值:
4 Q. e9 ^- ^& {: M- W8 ^. M. D; }x>0 ? x : -x9 {* m3 O/ G; Y$ |
; b- l, o. U- |6 w6 v1 e1 V
第七章 Actions里面的控制叙述
' {" }8 a# W& N _- _; q在 gawk 程式里面,控制叙述诸如 if、while 等控制程式执行的流
! D& E( {! J" \- l, r程。在 gawk 里的控制叙述与 C 的类似。
8 U2 P" K- }. c: h% a+ c d5 R6 [很多的控制叙述会包括其它的叙述,被包括的叙述称为 body。假$ @- p* F) g9 e' _) u
如 body 里面包括一个以上的叙述,必须以大括弧 { } 将这些叙述括起7 o, a8 f! S) b* D: G
来,而各个叙述之间需以换行(newline)或分号隔开。
# J% w/ }" V2 ?8 a2 t: \; f. h! H, @6 |, O1 y' i/ z9 _
7.1 if 叙述
3 _' k- P$ x& A: d1 E3 K' bif (condition) then-body [else else-body]
4 t; i1 u9 f# p3 z: {如果 condition 为真(true),则执行 then-body,否则执行 else-body。2 g( y* z, k: {! d, ?
举一个例子如下:( R+ C6 O! [9 i% B, h7 v7 V! S
if (x % 2 == 0)+ x+ p2 o- g O {0 D, K, E
print "x is even": ]2 b7 A( N% w' F! ?( a
else
2 e b* W/ ?( @/ yprint "x is odd"
5 @/ a* V2 o0 R9 S# u" D4 L6 ~ B6 D; J5 A
7.2 while 叙述
h) y7 ^4 x8 j" iwhile (condition)' a9 l" n! d0 U; S& C! k. `9 F
body
$ L( Z z+ _, k$ g4 jwhile 叙述做的第一件事就是测试 condition。假如 condition 为真则0 q) ^4 ~* i3 v
执行 body 的叙述。body 的叙述执行完後,会再测试 condition,假如2 C! ]2 k0 L: \
condition 为真,则 body 会再度被执行。这个过程会一直被重复直到- R* ~% T, H+ `2 R# e8 x
condition 不再是真。如果 condition 第一次测试就是伪(false),则$ S* Q' l% s$ f2 q# x
body 从没有被执行。, v6 I: w+ x, R4 ~( J
下面的例子会印出每个输入记录(record)的前三个栏位。
5 W0 T' T7 `- F7 ~' [! Pgawk '{ i=1$ C( ?( v$ `' W H. M$ j
while (i <= 3) {
* @( M$ ^! |2 m5 [$ @- tprint $i+ X- y! U0 }, o+ m% C) R4 f
i++
! E+ h( R! z4 l) l}
" U/ t+ w# x9 i$ Y; ^- B' t}'
/ }1 i z4 e$ S( k, d* S+ Q6 v
) x) W; I$ |6 g1 |! O7.3 do-while 叙述
i0 O `) H+ \3 cdo/ r. E3 y: ^ S8 k: @" r
body
9 d& ^' [8 M" v7 a! lwhile (condition)2 q( w" ^! a+ L" g( O
这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。
+ S' Y$ s9 a3 l$ f即使开始时 condition 是伪,body 也会被执行一次。
# S# J' e; v J5 _1 V下面的例子会印出每个输入记录十次。' L* j: X5 B; R3 s" W
gawk '{ i= 1
6 o$ G4 C- X* Z X( v- a7 bdo {4 F. [& B- n @/ E, |- h
print $00 m: K c3 t, \' ^
i++
! E. C" P8 \! M7 p- ]} while (i <= 10)
1 q: U% F- A5 X' {" [, I}'
1 k2 w9 r8 K, ^) @! T8 {# ^* l$ h
: M' x( k9 f) F7.4 for 叙述% w0 i% W8 F y3 Q2 n' g, O
for (initialization; condition; increment)
6 g% Q3 ]) B0 ]; I- [7 Q Xbody1 t& O# ^- L4 g0 U5 W4 N8 O
此叙述开始时会执行initialization,然後只要 condition是真,它
/ }: h5 s, ~* g8 T" u3 `会重复执行body与做increment 。
0 x! o: r3 ~9 j8 _; l5 \ H下面的例子会印出每个输入记录的前三个栏位。
% W; r7 e$ r* F! Z: j3 Z* ygawk '{ for (i=1; i<=3; i++)9 ?2 N. R5 |( M* g4 c; ?
print $i
6 o2 \ `8 c' b- h' x" G4 S) x}'
0 }( q0 a: _- l# S- h! o+ j) d
6 q+ u8 I+ Z8 @. O6 }% P+ z7.5 break 叙述
& I- E3 ^1 o* ?$ [break 叙述会跳出包含它的 for、while、do-while 回圈的最内层。
' i5 T, r. e2 q4 G下面的例子会找出任何整数的最小除数,它也会判断是否为质数。
- M: S+ [. d& O( j0 L7 W2 xgawk '# find smallest divisor of num
7 A$ |7 N& F2 ^( \% Q6 X( b: x1 v{ num=$1' s2 g# t7 M6 Z* S4 G
for (div=2; div*div <=num; div++)1 H# e" R/ o& q7 y
if (num % div == 0)
- a8 u# v" f8 x8 ~break/ Q1 @/ f( m! n3 u
if (num % div == 0)9 R9 ]9 k+ q% R# {% A0 X
printf "Smallest divisor of %d is %d\n", num, div+ a; I, u$ w- s, P7 q+ k$ P
else9 l& |8 \9 x: I, h' K
printf "%d is prime\n", num }'
) D- G$ `0 |: D$ E( V
8 Z! S! I( X$ B8 H7.6 continue 叙述& k6 J4 y: s q% M' f
continue 叙述使用於 for、while、do-while 回圈内部,它会跳
* X; `. O' i! ?6 Z过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。" i" T" l7 Z/ ~5 _7 \* x3 ^
下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。
- r. q, Y1 H" j8 R( ?gawk 'BEGIN {9 }% E7 m. N# @6 e& z- U
for (x=0; x<=20; x++) {
# M+ [: j$ {# q) h2 L3 `if (x==5)
8 I0 \- @1 _: K- B1 dcontinue
) p4 h( M9 t/ r, Cprintf ("%d",x)0 B s% w v# g( u# F1 o: V6 a# C
}; r: T( N v+ }0 n7 J3 g
print ""
& E0 Y! S S! ^ C5 \8 {# Y, y/ x+ X}'
) I: E+ q6 w9 j0 n& `/ B/ t/ N+ K; q6 E) O# j! q; `% f- x w( @
7.7 next 叙述、next file 叙述、exit 叙述# M- b+ D: V* g2 G0 ?) F
next 叙述强迫 gawk 立刻停止处理目前的记录(record)而继续下一
' F; Z' O6 J1 e# D" U个记录。
1 q n$ D# b( \+ S, c" onext file 叙述类似 next。然而,它强迫 gawk 立刻停止处理目前* l0 u# e6 z9 x+ {( V
的资料档。
* {( q/ L1 z, r& R; Q5 C6 [: @exit 叙述会使得 gawk 程式停止执行而跳出。然而,如果 END 出现
* e5 `: S; I3 x( b1 q" ?5 q3 O9 a3 \,它会去执行 END 的 actions。' i) h# l% a$ o' _7 {0 O
2 _: z, E% @ e) Y' X第八章 内建函式(Built-in Functions)
# Z3 G/ L3 J. y8 N" s" @内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建
% E% e" S" s2 `7 I$ x0 h/ p函式。
# z9 w& S+ Z% A1 U: C
: I$ k3 L& K2 }" `# U! D8.1 数值方面的内建函式
. h6 c- ?7 y4 Bint(x) 求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9)/ Z) A2 `- f, q. l M/ |2 V5 E
是 3,int(-3.9) 是 -3。
/ I4 k3 T( W" @sqrt(x) 求出 x 正的平方根值。例 sqrt(4)=26 K6 [2 s: N0 W
exp(x) 求出 x 的次方。例 exp(2) 即是求 e*e 。7 t% S% a: Y8 d9 J/ }
log(x) 求出 x 的自然对数。" t* n& q7 F, {1 S4 y
sin(x) 求出 x 的 sine 值,x 是弪度量。
! j% \7 @- H; ?7 ncos(x) 求出 x 的 cosine 值,x 是弪度量。/ l4 Y% m; x: s
atan2(y,x) 求 y/x 的 arctangent 值,所求出的值其单位是弪度量。5 x1 P6 Z9 Q" W
rand() 得出一个乱数值。此乱数值平均分布在 0 和 1 之间。这个
5 D1 |% o- {: T+ k% ~, ^$ \值不会是 0,也不会是 1。
1 J5 R& w8 J: u" _% t, S每次执行 gawk,rand 开始产生数字从相同点或 seed。
0 ?8 h. {8 O) p- Z* [srand(x) 设定产生乱数的开始点或 seed 为 x。如果在第二次你设
9 C$ V0 v0 k/ w$ b定相同的 seed 值,你将再度得到相同序列的乱数值。+ S. |- K2 _, f" g, \, R
如果省略引数 x,例如 srand(),则现在的日期、时间会0 n( J0 H; j+ A* o( h! m
被当成 seed。这个方法可使得乱数值是真正不可预测的。
8 a% U! W* I9 r) c# e+ w! q3 P: jsrand 的传回值(return value)是前次所设定的 seed 值。
! a- g+ e' Y; W4 w# y3 S! r" d
% H8 _1 _ t2 M1 D8 j8.2 字串方面的内建函式; ?+ g! K0 {2 y
index(in, find)
; Z) H+ h* {& h它会在字串 in 里面,寻找字串 find 第一次出现的地方,传回值是
( m* _, o* G. U2 p字串 find 出现在字串 in 里面的位置。如果在字串 in 里面找不到字! |: `! G7 S! n. D; O1 ]4 H' @
串 find,则传回值为 0。7 Z9 J$ ]; E/ K1 y4 e, a) r1 A
例如:
. @7 q3 L! Y! K* Z( Z# Fprint index("peanut","an")
1 C9 p; j: P' \' R1 U会印出 3。/ x' m6 ?- c0 g8 @
length(string)
, C. B p" [ w2 [2 S求出 string 有几个字元。2 J1 ?) R X( f5 b4 L* J
例如:' M+ }/ ]0 h3 ^, J% c
length("abcde")6 m$ K7 Q+ i, T/ K/ |, Q( D
是 5。
# r! W6 o k1 R' xmatch(string,regexp)
) I9 K; \$ r& v# {9 a* jmatch 函式会在字串 string 里面,寻找符合 regexp 的最长、最靠/ a6 y( }) j3 e0 G! g, a2 r( T
左边的子字串。传回值是 regexp 在 string 的开始位置,即 index' X- Q* G. x' m4 ?( y
值。
$ Q- A. k: u( g: a" Qmatch 函式会设定内在变数 RSTART 等於 index,它也会设定内在变/ X# K9 C; p0 d1 T
数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为; |; o# z- ~, a9 A% B. l5 d' k
0、RLENGTH 为 -1。9 B3 v$ q$ a/ Q8 B" `, L
sprintf(format,expression1,...)
& {! y$ [/ { A6 z6 b5 H举 printf 类似,但是 sprintf 并不印出,而是传回字串。
% @( F2 N' o5 ]3 y2 Z例如:/ u+ h' m, z5 x5 S* E! g4 H
sprintf("pi = %.2f (approx.)',22/7) P# }6 j% V$ V% _
传回的字串为"pi = 3.14 (approx.)"
. @" y F- I. t6 `7 N' _0 Gsub(regexp, replacement,target)
. c. Y3 w( K& k g4 N) T在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,
; W6 p. y3 q, P! [0 k" b以字串 replacement 代替最左边的 regexp。
: \3 y" v! N" s1 C0 ^& q例如:& Q, C: `2 p$ l! w7 I/ ?1 p! J7 \
str = "water, water, everywhere"
/ `1 ~. I. r3 X: L: asub(/at/, "ith",str) Y. U- A, t0 I9 M. L4 N
结果字串str会变成0 B# D3 y# Q% U& B) L+ O
"wither, water, everywhere"
" E, W& Z: u7 B0 ggsub(regexp, replacement, target)
1 N- {# i) n3 M8 e9 Jgsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的& T7 U! Y* m: Y. b5 u
所有地方,以字串 replacement 代替所有的 regexp。5 `9 T: D) G$ c' C' V; q' q
例如:- k& @( w* w5 |
str="water, water, everywhere"
$ I$ d5 r* V4 D0 kgsub(/at/, "ith",str)
9 W7 t& ~* ?7 G. w结果字串str会变成
, s% A- @% K# m% C( f9 Y'wither, wither, everywhere"
. l$ B, k* F9 D4 W! [) Tsubstr(string, start, length) z5 }) b* ]( m- u/ I
传回字串 string 的子字串,这个子字串的长度为 length 个字元,8 J0 E# O) o7 O6 @! R
从第 start 个位置开始。 y) z- s3 k" Z( J
例如:
$ ?5 ]- X3 |. p; G/ Ssubstr("washington",5,3)
- P9 K7 w1 Z7 O8 r/ t, B传回值为"ing"
9 ?& f/ v8 G* F2 N3 ~& h如果 length 没有出现,则传回的子字串是从第 start 个位置开始
% g, K3 Y9 ~9 f. J# Q至结束。' ?' f; p( L% W1 K; W r% n5 X5 B
例如:
. X- t5 D6 f+ F p+ Lsubstr("washington",5)* x- y" z- o% E8 A% ~3 }* ?
传回值为"ington"
$ `' k: l0 q/ L' O9 {% Ptolower(string)" k( k R' c3 L8 ]4 F* m
将字串string的大写字母改为小写字母。' ~# {; q# g- j/ e* [# R7 P0 z6 k
例如:& {- T3 y _/ {, \; U7 _% [
tolower("MiXeD cAsE 123")
# r, l4 `& J3 D$ E传回值为"mixed case 123"8 V' F- Y7 h7 q6 _# {; n
toupper(string)
/ I$ Q2 k" g, b7 b将字串string的小写字母改为大写字母。
$ l% v' p ?/ P- D' S例如:1 ~& z* b( S6 D M6 L* x
toupper("MiXeD cAsE 123")% {6 m' u# G- C: b
传回值为"MIXED CASE 123"
7 ?- R# F; u1 C, L1 p x3 k4 r6 H. N3 \ @
8.3 输入输出的内建函式: L) ]4 D5 U# q9 S% ~
close(filename)
+ Y8 _. G$ b: l' _% V1 I- ~将输入或输出的档案 filename 关闭。' D' M; e5 `3 n( {
system(command)
9 C) y1 ?4 E% w2 c此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk
6 U8 i E: S# |9 X. C程式。
$ K3 p y X, L$ b" j* K3 l# O例如:
: Z4 X' h0 I8 ?& |0 F# EBEGIN {system("ls")}
0 v% j6 ^2 J/ x- k0 s j
# C5 S0 X+ f& j+ u第九章 使用者定义的函式(User-defined Functions)) p j7 E) a5 D
复杂的 gawk 程式常常可以使用自己定义的函式来简化。呼叫使用" |/ y. w8 ]; H0 F5 ^
者定义的函式与呼叫内建函式的方法一样。
& q) u$ d- ]( k; A
- a5 V6 H# {6 \8 L: B( O2 [9.1 函式定义的格式; q: F8 ~7 y- \" ?& X
函式的定义可以放在 gawk 程式的任何地方。& p% h+ F4 u- E k" R" F2 V) }! m
一个使用者定义的函式其格式如下:$ ^$ _, p; P5 L m4 Q
function name (parameter-list) {& S+ p7 f# i0 M8 i! n0 C: w: p! j
body-of-function
8 n5 [! B3 I* Z* g2 P}# L4 P5 }( Z+ M" O5 N% W
name 是所定义的函式之名称。一个正确的函式名称可包括一序列的字
3 o( v7 Y2 v$ m母、数字、下标线 (underscores),但是不可用数字做开头。* o& I& `6 a3 y; Z
parameter-list 是列出函式的全部引数(argument),各个引数之; F* m" q5 u0 g9 {3 a5 r9 h+ A; C
间以逗点隔开。! z* }! Q+ U; p% z
body-of-function 包含 gawk 的叙述 (statement)。它是函式定义
* w, o5 a- r! x; |+ O' c7 Z里最重要的部份,它决定函式实际要做何种事。+ ?. t+ Z; H# h" ^& ~4 v" F- O
$ |5 ^. c$ s% x
9.2 函式定义的例子% E$ i1 z) {& Q" w1 e: h
下面这个例子,会将每个记录的第一个栏位之值的平方与第二个
5 C3 L2 W' l7 M栏位之值的平方加起来。
* W+ {9 e3 g9 h' k* F$ d- r4 u{print "sum =",SquareSum($1,$2)}
& m7 z% l8 y4 G) Kfunction SquareSum(x,y) {
( p/ [* K x9 O6 }6 b* Usum=x*x+y*y
6 b. n5 w; H" t* [. r2 Ereturn sum
4 m$ c* j/ k/ p: X}5 V% g4 m3 d3 ?, U/ [8 d6 O
. H/ n, G1 F& B* Z2 b& `第十章 □例7 k* Z* h; b0 E1 B5 b
这里将列出 gawk 程式的一些例子。
2 x4 v+ A8 D9 u# E* R* D/ Xgawk '{if (NF > max) max = NF}
: V& g! [% M7 l5 vEND {print max}'
# Z, | e( i/ o此程式会印出所有输入行之中,栏位的最大个数。
2 V8 ^$ r6 r P$ Igawk 'length($0) > 80'
. l* R7 _6 N/ Y0 q8 O3 M此程式会印出一行超过 80 个字元的每一行。此处只有 pattern 被 P' z7 W( s; g9 ?. ]: E: L% X
列出,action 是采用内定的 print。" X# y! p9 K" _; q
gawk 'NF > 0'
4 I8 ^ o2 _ V! c对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
, N! u4 q0 C$ T3 m单的方法,将一个档案里的所有空白行删除。
$ t1 ~, N1 u8 z# q: s/ W lgawk '{if (NF > 0) print}'4 @* S8 U7 K# `: Y, z- A6 ~6 v
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
1 a" [; y% j3 f" P' R( [9 Q单的方法,将一个档案里的所有空白行删除。0 N6 k9 |! X* |+ B" p+ K
gawk 'BEGIN {for (i = 1; i <= 7; i++)
* q: ~6 q4 R& G1 |: c: `7 G+ jprint int(101 * rand())}'. h* T( u1 L" f- P, N G
此程式会印出□围是 0 到 100 之间的 7 个乱数值。' V% u: s" f; \+ q" O0 s j5 p) g' v+ o
ls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
9 e# S, G; x0 g* d i6 C6 e4 o$ g此程式会印出所有指定的档案之bytes数目的总和。
e& ?+ Y: O0 h, R* Rexpand file | gawk '{if (x < length()) x = length()}( @" \0 Z# m8 r2 H- V# B
END {print "maximum line length is " x}'
0 }6 u+ `0 X$ g1 t3 @; L5 v" S此程式会将指定档案里最长一行的长度印出。expand 会将 tab 改* s( u1 x0 T3 y0 m: r& N5 O ]
成 space,所以是用实际的右边界来做长度的比较。! I. J- c( A. w H! p
gawk 'BEGIN {FS = ":"}
" E2 A ]8 h: K4 j6 Z( w{print $1 | "sort"}' /etc/passwd
* w3 _' }6 |, B3 N9 J此程式会将所有使用者的login名称,依照字母的顺序印出。
5 H$ o7 D$ d$ Rgawk '{nlines++}$ H# R8 U" r( c% D. r9 R
END {print nlines}'! v- x' q( w1 |
此程式会将一个档案的总行数印出。2 l9 N5 f2 u) B' y$ T
gawk 'END {print NR}'
; E* n7 s1 a; ], S: k1 y此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk6 f1 y+ z, ~, ?5 F& H5 O8 y6 A V
来做。
: _% O" n7 U& ]1 N2 f* P* \gawk '{print NR,$0}'
/ R9 j# @- t; E4 @4 q此程式印出档案的内容时,会在每行的最前面印出行号,它的功( C' a0 m" t9 h6 _ ^5 \! w2 F
能与 'cat -n' 类似。% ^ b- c3 _+ \# @
" s+ D* B2 t/ Y' g$ u
第十一章 结论
2 E) z& o( I! _5 ]" s; {gawk 对於资料的处理具有很强的功能。它能够以很短的程式完成3 f+ n% Z8 I4 u0 m v
想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件
3 f- A. n# T, ^. S1 G- e工作,以 gawk 程式来写会比用其它程式语言来写短很多。 c+ U) o2 S0 e, l) W1 X! G+ _
gawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使# |( z& a1 _4 L, M1 B
用。 |
|