TA的每日心情 | 奋斗 2019-2-12 09:32 |
|---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到 累计签到:1 天 连续签到:1 天
|
|
马上加入,结交更多好友,共享更多资料,让你轻松玩转电力研学社区!
您需要 登录 才可以下载或查看,没有账号?立即加入
×
GAWK; ?# @2 V5 q6 L k+ x3 [8 u( G
第一章 前言2 j4 w9 z6 B/ ~8 T' e; o
第二章 简介/ q. o* V9 T0 n/ O
第三章 读取输入档案9 h0 @5 x$ `5 A) W
第四章 印出' p' }6 q) d& W4 ~8 X8 J
第五章 Patterns
$ f% v6 ^( E c第六章 算式(Expression)作为Actions的叙述( A/ j& r# ?6 m
第七章 Actions里面的控制叙述4 y. C K1 B5 v1 [/ j1 P
第八章 内建函式(Built-in Functions)& y: R- B, o- L; g5 @( N+ G
第九章 使用者定义的函式% f5 f8 Y u5 \6 i
第十章 □例
2 W s( j4 ^% L# T! t* R第十一章 结论 |6 q! w$ G' ^0 B' V9 r
- C% A: T; T: }2 f=======================================
- C' X. W$ L4 N8 N第一章 前言: w0 ?, r! ^8 ]! l$ T2 N' D
awk 是一个程式语言,对於资料的处理具有很强的功能。对於文
, ?& R/ }' Z. ^+ L8 I字档里的资料做修改、比对、抽取等的处理,awk 能够以很短的程式
. o w; g" q* u8 g, o$ v轻易地完成。如果使用 C 或 Pascal 等语言写程式完成上述的动作,
) x e [& c/ y5 o A会不方便且很花费时间,所写的程式也会很大。
r( e. ~! @4 s; E/ W/ f% Y1 b- mawk 能够依照使用者的定义格式来分解输入资料,也可依照使用: |/ G' K+ W9 y- ?3 R3 F
者定义的格式来印出资料。
@- p% e# n- G7 U% d# f: K% L& N; hawk 名称的由来是由它的原始设计者的姓氏之第一个字母而命名
( Y5 Q: _4 h" B8 L:Alfred V. Aho, Peter J. Weinberger, Brian W. Kernighan。1 n5 r2 b) X+ s! O; Q, b5 M
awk最初在1977年完成。一个新版本的awk在1985年被发表,它的功能5 I1 N6 |# Z: T3 L; t9 r \( D+ q
比旧版本增强不少。& Q9 L0 R: S- v# O2 D/ \; y0 d' T
gawk 是GNU所做的 awk,gawk 最初在1986年完成,之後不断地/ k, X" ^! v+ E
被改进、更新。gawk 包含 awk 的所有功能。& T: B& O8 G0 A7 q- s8 i' M- T
往後的 gawk 将以下面的2个输入档案来做例子说明。
) S2 ]8 x: i" f$ W- V2 M9 M1 {档案'BBS-list':
9 u% R8 G- \' S2 K4 Caardvark 555-5553 1200/300 B
4 I4 }& `& r" c% p' galpo-net 555-3412 2400/1200/300 A
& b: L/ J+ W! X6 n: @* Z) J3 @barfly 555-7685 1200/300 A5 S. R' p8 E4 x0 ~9 s4 [
bites 555-1675 2400/1200/300 A
! }( c* J4 ]7 D T7 N6 J# ~0 O) Ucamelot 555-0542 300 C% @" X% [. V) y" F" I! b
core 555-2912 1200/300 C1 S4 z/ }! D F5 Z: o2 r1 H$ x
fooey 555-1234 2400/1200/300 B
7 x, b, y6 H: j# E# `foot 555-6699 1200/300 B2 Y2 E6 Y5 h6 k5 [7 m
macfoo 555-6480 1200/300 A
; {: a: N9 r9 E' t6 f y* Zsdace 555-3430 2400/1200/300 A1 o$ u V! |. W. t$ @
sabafoo 555-2127 1200/300 C
: b; t+ T6 w; O: b: C档案'shipped':
p: l$ M8 U5 p4 u' sJan 13 25 15 115
0 I: b8 t- H! EFeb 15 32 24 226% \, [6 B R% H3 a$ [) x
Mar 15 24 34 2284 E4 `# ] w% L# M. V k
Apr 31 52 63 420
* I. j, b2 b+ n0 z, E* EMay 16 34 29 208% K' |: s* R5 l1 t' u7 M
Jun 31 42 75 492
" L3 B6 I) f) o( m# \$ ^Jul 24 34 67 4363 m9 a6 h" x9 M& d+ D
Aug 15 34 47 316/ h$ E/ z8 F8 R, R, F( g
Sep 13 55 37 277
. i' j( i q+ a5 O' eOct 29 54 68 525
) N1 V7 U" j: {' L; zNov 20 87 82 577
- _1 M( z4 u; ~; P" EDec 17 35 61 4015 X( ~3 v3 R" o) N4 d
Jan 21 36 64 620+ n3 d3 N1 d# I3 o( M2 G, `7 W6 S
Feb 26 58 80 652
5 W; X, Z6 W; m, I/ MMar 24 75 70 495# P F" T$ J! ?$ _. k8 \/ Q
Apr 21 70 74 514
" W0 N; b; U; O+ ~- f4 I5 n9 t
% u$ W% |4 i; X G第二章 简介9 y8 {/ V3 b" z. j' |9 h" y
gawk 的主要功能是针对档案的每一行(line)搜寻指定的 patterns
& p8 k. O& e% L3 ^。当一行里有符合指定的 patterns,gawk 就会在此一行执行被指定; E& V7 n& E, i2 L+ b6 o( ^
的 actions。 gawk 依此方式处理输入档案的每一行直到输入档案结. I' y |/ h; m$ q$ \4 W: K& C& a
束。% j+ S1 z; k# p9 ~8 v1 K
gawk 程式是由很多的 pattern 与 action 所组成,action 写在
7 Y, A, o {% j2 R' E大括号 { } 里面,一个pattern後面就跟著一个action。整个 gawk 程 C5 t% a& T( M
式会像下面的样子:
4 f- W/ v+ D( ypattern {action}
$ Y% Z1 X+ ~3 q7 n! G1 F, ipattern {action}
9 q% }2 Y2 }( h9 D5 S在 gawk 程式里面的规则,pattern 或 action 能够被省略,但
5 ~) X2 C' s' m; F, n8 y是两个不能同时被省略。如果 pattern 被省略,对於输入档里面的
5 e; h3 h) j2 O) ~0 G# d每一行,action 都会被执行。如果 action 被省略,内定的 action7 d2 {9 r2 V, [
则会印出所有符合 pattern 的输入行。
9 j. ?% V2 m j. T
$ v- \1 T# @: B' P" P2.1 如何执行gawk程式
; G* N+ l* s1 o$ ?# R; c基本上,有2个方法可以执行gawk程式。/ z) m: B, E3 \( g1 J4 r
□如果 gawk 程式很短,则 gawk 可以直接写在 command line,如下所示:
- @- x% t Z- C- Lgawk 'program' input-file1 input-file2 ...: _9 E! x' ]$ ~/ N, V+ D2 K
其中 program 包括一些 pattern 和 action。
) h0 V3 O( C+ r, _1 B□如果 gawk 程式较长,较为方便的做法是将 gawk 程式存在一个档案,5 C; q* ?" G' L! P+ d7 Z: B& [
即 patterns 与 actions 写在档名为 program-file 的档案里面,执行
4 j& Q# h" z0 `! Y! Xgawk 的格式如下所示:* |* l: @4 {9 }/ a" f: S
gawk -f program-file input-file1 input-file2 ...1 f2 _9 Z* B" d- [( r0 M% O
gawk 程式的档案不止一个时,执行gawk 的格式如下所示:; o! K* Y I+ k' x* Z( d- j' n5 r
gawk -f program-file1 -f program-file2 ... input-file11 _3 B6 \! a$ X C* @, H; M
input-file2 ...
0 J+ ?# y; [3 D& o6 m7 h+ Y) S- l- m/ E6 r
2.2 一个简单的例子; W1 C, H1 y8 n. U0 M$ c
现在我们举一个简单的例子,因为 gawk 程式很短,所以将 gawk 程1 Q8 I& C* i! L) _4 F2 B& w
式直接写在 command line。
0 t/ K" X" i2 ?gawk '/foo/ {print $0}' BBS-list
, B$ z: K6 }, t& B1 `实际的 gawk 程式为 /foo/ {print $0}。/foo/ 为 pattern,意思为搜. u: }) {' b0 [ x
寻输入档里的每一行是否含有子字串 'foo',如果含有 'foo' 则执行 action。
1 f: o4 G3 p3 eaction 为 print $0,是将现在这一行的内容印出。BBS-list 是输入的档案。
6 ?. W! Z) R! D) B5 h执行完上述指令後,会印出下面的结果:
$ F F4 S% h8 ifooey 555-1234 2400/1200/300 B3 C7 h. ~: c# C. l. o; j. \1 Z- y
foot 555-6699 1200/300 B
8 {8 _ }" y' Amacfoo 555-6480 1200/300 A7 ^' d/ n6 {' J6 j6 ^
sabafoo 555-2127 1200/300 C' K( q0 H [% h5 D. J/ x( ~
: Z9 |" M) I) X. b" Z0 {2.3 一个较复杂的例子
* h8 d0 u) x2 n @gawk '$1 == "Feb" {sum=$2+$3} END {print sum}' shipped
2 \! |0 n- ^. ]6 a6 F0 T$ b! l现在这个例子会将输入档 'shipped' 的第一个栏位与 "Feb" 做比较
5 A0 ?4 h8 Q7 w: ?, C/ u,如果相等,则其对应的第2栏位与第3栏位的值会被加到变数 sum。 R% G5 {+ E+ S
对於输入档的每一行重复上述的动作,直到输入档的每一行都被处理
9 x6 N9 h, h& F; c2 m: u过为止。最後将 sum 的值印出。END {print sum} 的意思为在所有的输
$ e" D( ?' Y, M) O9 C入读完之後,执行一次 print sum 的动作,也就是把 sum 的值印出。
. c& e0 N/ w# y' w7 m, P下面是执行的结果:& {& _* E/ g' U& S8 L
84
9 R2 } `: i( ~8 q( T3 x8 v
4 E0 Q0 p! D+ U M第三章 读取输入档案
' Z4 |4 n* W" d5 X; x+ @gawk的输入可以从标准输入或指定的档案里读取。输入的读取单' b: |; i8 H8 j B& C
位被称为”记录”(records),gawk 在做处理时,是一个记录一个记* [3 L% B4 }4 Y* c$ K
录地处理。每个记录的内定值是一行(line),一个记录又被分为多个. g6 B2 r' w$ v. A& P
栏位(fields)。, s$ u3 G* H5 c+ ?9 i0 C
! T9 [. r+ G Y+ i% B* k6 P! p! E i
3.1 如何将输入分解成记录(records)
6 Q2 K K2 w: v2 M, ~* Agawk 语言会把输入分解成记录(record)。记录与记录之间是以7 Z( j" f3 F- z1 w* k& D, Y, P
record separator 隔开,record separator 的内定值是表示新一行的
U! C6 {0 h+ P% A8 P字元(newline character),因此内定的 record separator 使得文字
) P6 ]5 n# E$ Z的每一行是一个记录。
7 ]( K5 I6 ]+ Y$ A8 V! G+ k7 \1 Urecord separator 随著内建变数 RS 的改变而改变。RS 是一个字串,9 B8 G, Z% V: t: [1 U1 H; F( B% Q
它的内定值是"\n"。仅有 RS 的第一个字元是有效的,它被当作 record
3 W: m% t: X- P. b, N mseparator,而 RS 的其它字元会被忽略。0 u Z2 b! I$ H/ j& M1 H# U
内建变数 FNR 会储存目前的输入档案已经被读取的记录之个数。内7 W$ a: u3 q" S' l; C7 ^6 P
建变数 NR 会储存目前为止所有的输入档案已经被读取的记录之个数。8 b! m8 V, F: R9 C0 N
: U7 y* t( a2 C5 t- y0 ]3.2 栏位(field)
$ O; P" c3 I. m, agawk 会自动将每个记录分解成多个栏位 (field)。类似於字在一
% Q! n" b8 R: m* _* W! C% k行里面,gawk 的内定动作会认为栏位之间是以 whitespace 分开。在
' c" }8 S; `# j3 G | A% {gawk 里,whitespace 的意思是一个或多个空白或 tabs。
9 z- E G9 @1 n. l ~( z5 X, ~& I在 gawk 程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位. N; A1 Q( F ?9 f: ~; J/ T
,依此类推。举个例子,假设输入的一行如下所示:2 ~. \- b3 ~; x
This seems like a pretty nice example.) \8 U6 t! ?7 @9 Q. i
第一个栏位或 $1 是'This',第二个栏位或 $2 是 'seems',依此类推。( y1 s2 ?0 a) ?+ r
有个地方值得特别注意,第七个栏位或 $7 是'example.'而非'example'。
5 T/ j! n7 ~/ s- Y& @不论有多少栏位,$NF 可用来表示一个记录的最後一个栏位。以
( W5 y5 `' \3 N% e上面的例子为例,$NF 与 $7 相同,也就是'example.'。
8 T6 z1 Z) M1 c* d% rNF 是一个内建变数,它的值表示目前这个记录之栏位的个数。1 j/ ?; B8 {* {5 {7 i- `# \) [+ z' J( E9 r
$0,看起来好像是第零个栏位,它是一个特例,它表示整个记录。5 Z! p( H1 _4 h
下面是一个较复杂的例子:
8 @1 K5 o# |+ R7 cgawk '$1~/foo/ {print $0}' BBS-list7 W' [) F! G$ e7 E) Q6 F" i) l; b
结果如下:
4 L5 [& n& a. Q1 s$ w2 p! Qfooey 555-1234 2400/1200/300 B: f4 Z) }8 g, @4 r: ]$ P
foot 555-6699 1200/300 B7 }) b, y% X# V, _9 ?5 t
macfoo 555-6480 1200/300 A
! h" o; i t* i! _sabafoo 555-2127 1200/300 C1 e2 T o- j* H
这个例子是把输入档'BBS-list'的每个记录的第一个栏位作检查,如
% Q* `4 E8 a. a8 W( F% L$ d: n果它含有子字串'foo',则这一个记录会被印出。8 `* U: a0 e" w! j# n
( ^" Y$ _' W4 @* v, O3.3 如何将记录分解成栏位, U9 |1 z8 w2 Y! b- ^8 |6 Q
gawk 根据 field separator 将一个记录分解成栏位。field sepa-* R1 h' N& W1 A) M; [4 H; H
rator 以内建变数 FS 表示。) P* F& _6 x; P% t& V% f+ R
举个例子,假如 field separator 是'oo',则下面的行:9 N- E0 h e2 C% @
moo goo gai pan6 g4 D$ U# r R$ V# F
会被分成三个栏位:'m'、' g'、' gai pan'。* t6 _: y$ O! b. `
在 gawk 程式里,可以使用'='来改变 FS 的值。例如:
. H% Q; S: z, W2 A7 Z, tgawk 'BEGIN {FS=","}; {print $2}'
( k+ m, Z8 [) F& G( w" b9 S输入行如下:& K- n" @4 d+ P9 U8 c& o: u8 P7 I
John Q. Smith, 29 Oak St., Walamazoo, MI 42139
. \) m. C/ E- m. O6 }4 S9 W) c$ p执行gawk的结果将印出字串 ' 29 Oak St.'。BEGIN 後面的 action 会在6 o* s! J. l) d; j
第一个记录被读取之前执行一次。: @" I! X$ ]9 L/ ^, D
. c: |/ A* B( g+ n4 r; w
第四章 印出
6 q3 u9 f% Q, U! z/ o+ m8 ]) R在gawk程式里,actions 最常做的事就是印出(printing)。简单
6 D: f! q# I! [( @的印出,使用 printe叙述。复杂格式的印出,使用 printf 叙述。
' @6 i. E& h* @7 b* K
, n3 w& V$ Z& t. L4.1 print叙述, M# v8 F" m& n' ^( }* y
print 叙述用在简单、标准的输出格式。叙述的格式如下所示:% h q. Q/ F8 @- D p3 |
print item1, item2, ...# B, [6 Y: Z8 I
输出时,各个 item 之间会以一个空白分开,最後会换行(newline)。
9 C! q, f8 a6 H: |! N% L: y7 y如果 'print'叙述之後没有跟著任何东西,它与'print $0'的效
( G* l! Z6 g0 M- Y# s5 [/ F. k果一样,它会印出现在的记录(record)。要印出空白行可使用'print
- [7 z+ ` W7 B- B n! m""'。 印出一段固定的文字,可用双引号将文字的两边括起来,例如
- Q2 G( t/ ^% E3 l u+ y* {'print "Hello there"'。
5 X# V% `: T! z9 E' W这里是一个例子,它会把每个输入记录的前二个栏位印出:, Z9 v7 ~& l# D7 w+ t {+ ~
gawk '{print $1,$2}' shipped& l2 B6 h* u( b6 R
结果如下所示:5 M1 [% a6 E* P% ?# ^6 \
Jan 13! o1 Q8 F' x/ M/ g6 |9 z9 }0 I) r
Feb 156 i2 b- ~' f, W5 b* w1 ?' k: m7 i. x
Mar 15: o( O. \2 v: [: V9 L4 @' c
Apr 31
: U8 z- J# a8 A! \9 l5 NMay 16) N* L# o% L! f9 \
Jun 31! \7 X" a) p5 n* G. Y' Z
Jul 24$ ]+ }# b; K) N' i9 `
Aug 15
3 {0 r/ o9 J, u' E) j: x( WSep 13) k. B% w* @) N
Oct 29
( V0 B Z" V& iNov 20
0 C" k: z! t6 i. [ ~; r* r, VDec 17) ]" d g: }+ y, Y: i2 }4 Y0 }
Jan 21
: Z9 [# Z( {" U7 c; w; e6 SFeb 26; f; l5 c' U7 T
Mar 24) v9 `+ D! v0 i
Apr 21) t6 w& Z( ]& p" l$ S2 l5 ?
+ O1 @& l; E( V/ _. c" O4.2 Output Separators
* L6 E9 N/ J5 z* d. [6 Z5 P前面我们已提过如果 print 叙述包含有多个 item,item 之间
( P, W5 R# O3 R9 j! J6 B5 ~/ P) j用逗点分开,则印出时各个item会被一个空白隔开。你能够使用任何
: M* b8 `; k# V! q8 e& [的字串作为 output field separator,可以经由内建变数 OFS 的设
3 z9 w+ M3 b# Z+ p3 i1 K定来更改 output field separator。OFS 的初始值为" ",即一格的
6 h1 e Z: u; Q: K0 ^) R空白。
( S* v+ P p$ [整个 print 叙述的输出被称为 output record。print 叙述输5 i7 F0 \& b2 J
出 output record 之後,会接著输出一个字串,此字串称为 output' L4 i$ a. R: y2 f8 S" {; ~
record separator。内建变数 ORS 用来指明此字串。ORS 的初始值
3 T# E" v* S9 L( o- ]5 ?5 W h4 [! l为 "\n",也就是换行。
- z$ s' k4 ?' a! O& R6 m, c下面这个例子会印出每个记录的第一个栏位和第二个栏位,此二/ z6 s7 W W# q% W
个栏位之间以分号';'分开,每行输出之後会加入一个空白行。( f5 d2 O- b1 O6 I; g
gawk 'BEGIN {OFS=";"; ORS="\n\n"} {print $1, $2}' BBS-list
1 b1 L/ ?' c2 r2 L结果如下所示:
% u: O; R8 a6 R3 K raardvark;555-5553
`; \% U3 q0 d {1 \" \8 Z: balpo-net;555-34121 `+ t5 Z& O: S/ V: V* l
barfly;555-7685
" M) k& u& v- T8 f: Wbites;555-1675
. S; o3 _2 _% p; B; Zcamelot;555-0542% c% q, |! ~5 s
core;555-2912( M) e1 b. D' i1 r: D6 L$ R+ k
fooey;555-1234
& Z3 f, H: B$ t; ]8 m& z/ Ifoot;555-6699. y9 Y; [: Q2 u. @1 ^
macfoo;555-6480
6 q z( |$ g+ Dsdace;555-3430% N+ h2 m- [. s: b' ^% Z
sabafoo;555-2127
1 r9 ]4 K0 q# s! v2 n6 ]
4 Z+ z2 E7 U" v- C3 W( _2 W& z) s4.3 printf叙述
# I) @" W2 ]9 q. l( hprintf 叙述会使得输出格式较容易精确地控制。printf 叙述可以+ F; _* ^3 g9 O. x/ z1 _
指定每个 item 印出的宽度,也可以指定数字的各种型式。4 v& s/ D9 m E" W5 X7 Q z
printf 叙述的格式如下:# H+ t* X @5 |# g. G' g
printf format, item1, item2, ...- O: ~9 f1 N$ j1 z$ [; p
print 与 printf 的差别是在於 format, printf 的引数比 print3 S& {6 u. F: H4 K
多了字串 format。format 的型式与 ANSI C 的 printf 之格式相同。7 N' K% s' C) L1 U2 d, ] f
printf 并不会做自动换行的动作。内建变数 OFS 与 ORS 对 printf 叙
: w# U1 k. y- |$ E& A/ a& ~述没有任何影响。
. J7 x* a& }6 w2 w; v' E格式的指定以字元'%'开始,後面接著格式控制字母。* n' t! G; @- Y. ^1 Y
格式控制字母如下所示:: T/ E( b6 S; M; c& g: a
'c' 将数字以 ASCII 字元印出。
% Q4 k4 k4 h% S [* E例如'printf "%C",65'会印出字元'A'。
/ q5 \3 _2 Z4 H+ X% D, S'd' 印出十进位的整数。
. _# {4 g1 T/ q2 j1 r; E l2 x'i' 印出十进位的整数。9 a/ e5 m- _( j) U
'e' 将数字以科学符号的形式印出。
2 ^7 W5 J1 j; j例如( \6 w; y% z, K$ S
print "$4.3e",1950
4 L7 [/ W. I7 U: H' f结果会印出'1.950e+03'。/ _1 B6 i2 t5 r9 b S
'f' 将数字以浮点的形式印出。) k8 k) U9 ]1 ~
'g' 将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果
( I+ w% J* z& R: _大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印" w0 o ~/ |* z' U3 g2 H
出。0 w3 |; i, x+ r* ^
'o' 印出无号的八进位整数。" M0 F" @1 ^0 ^$ e6 d7 f
's' 印出一个字串。4 X! W. q3 P. d
'x' 印出无号的十六进位整数。10至15以'a'至'f'表示。+ ~7 @7 G$ I+ r# B
'X' 印出无号的十六进位整数。10至15以'A'至'F"表示。
) f! a& p. t8 E'%' 它并不是真正的格式控制字母,'%%"将印出"%'。8 T. N; l! K# n. @; X
在 % 与格式控制字母之间可加入 modifier,modifier 是用来进一( w' s6 F, i. ~: @8 I+ \! A' p
步控制输出的格式。可能的 modifier 如下所示:
% `0 v$ L5 N! m. z; k) K'-' 使用在 width 之前,指明是向左靠齐。如果'-'没有出现,则会在 f8 [ Y& H8 P
被指定的宽度向右靠齐。例如:' h9 C3 d0 u5 h& o6 ~* R
printf "%-4S", "foo"3 ?& K& x; E7 `( m, x
会印出'foo '。
6 \8 Z8 n; Y$ t/ K* V'width' 这一个数字指示相对应的栏位印出时的宽度。例如:
8 G- \2 V3 |2 @8 B# uprintf "%4s","foo"7 ~: F. c; s7 l+ {3 P
会印出' foo'。" J: J: [) q" ?- L1 Z+ F0 h
width 的值是一个最小宽度而非最大宽度。如果一个 item 的) S; C# \6 i! r
值需要的宽度比 width 大,则不受 width 的影响。例如/ u, Q# C: ?% h+ ~
printf "%4s","foobar"& R% J/ p; v) G& s' K$ [
将印出'foobar'。4 \3 i# C+ m, |. |( u
'.prec' 此数字指定印出时的精确度。它指定小数点右边的位数。如
5 p; _" c% g5 O K3 P- Z* ^3 \果是要印出一个字串,它指定此字串最多会被印出多少个字
4 i, i4 D3 @* v元。- Y4 k% x: w! h- L4 I
" ?1 X( K3 W" h5 T9 I+ V% ?第五章 patterns7 b# I2 A# F5 E% Y
在 gawk 程式里面,当 pattern 符合现在的输入记录(record),其
& d. R: q+ g) Z/ H; q! @/ a相对应的 action 才会被执行。
$ S5 J7 U# b& P: F& m/ j( [8 j5 D% }% o& U. Q# t
5.1 Pattern的种类- u5 G2 G& C9 c2 v* E, D
这里对 gawk 的各种 pattern 型式作一整理:
3 m. A$ D6 n2 w* E/regular expression/. i7 c& ` N6 J; R; h3 G( G
一个 regular expression 当作一个 pattern。每当输入记录 (
( X* q6 D/ b* u* N0 [3 rrecord)含有 regular expression 就视为符合。
1 |3 [$ M! G9 m8 ]8 t7 qexpression! Z6 s) n0 B; i3 o3 z/ Y
一个单一的 expression。当一个值不为 0 或一个字串不是空的,
, [! d: H5 P2 N0 a则可视为符合。) j8 [ Q4 p8 ?
pat1,pat2
/ K) @& N) e& u* ]& R一对的 patterns 以逗号分开,指定记录的□围。1 G6 T3 U a- T( `: A- a6 ]" ]
BEGIN( R3 s. }& [) x0 a! g6 z
END( N' n" B/ q9 x3 v* R" J7 S
这是特别的 pattern, gawk 在开始执行或要结束时会分别执行相
Y2 c+ J. n+ F5 j对应於BEGIN或END的 action。7 C: w7 y+ i. z1 r+ P. d
null
, Y2 S) d- r% r6 _9 z7 y2 p这是一个空的pattern,对於每个输入记录皆视为符合pattern。$ l$ e0 l2 ?6 \8 S2 O' w/ ^
' E; t( y( @ Y; {* w5.2 Regular Expressions当作Patterns
( |4 S* _4 w5 h% \; U$ o6 L+ K% F7 c" S5 K一个 regular expression 可简写为 regexp,是一种描述字串的方. I6 h" L/ O: K* f j, q8 Q6 N
法。一个 regular expression 以斜线('/')包围当作 gawk 的 pattern。
; x0 w3 _6 X3 C9 a% X- e/ I如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,
1 Y* e0 L) T" V0 \* R/ n" o, N对於任何输入记录含有'foo'则视为符合。
- _. q* Y, Z/ ~0 x& X下面的例子会将含有'foo'的输入记录之第2个栏位印出。$ z* D C& p- ~: C% I* G
gawk '/foo/ {print $2}' BBS-list
n2 J1 Q1 a. h" D8 Q8 z' h结果如下:
p. {/ X' s8 P( S; q- n/ d555-12343 I5 m1 N- o6 h& b) f
555-6699
3 M/ I$ k4 p5 a% S$ Q# Y/ Z) [! C, }555-6480
7 t" q, ^% B3 L% k( p4 i" J7 u555-2127
4 I$ c7 Q5 A* @: W5 aregexp 也能使用在比较的算式。6 j" X' A) M6 P1 K% E2 o
exp ~ /regexp/
9 X2 Z, u5 E3 l' ]& `/ u如果 exp 符合 regexp,则结果为真(true)。: H8 l1 J# ]. N
exp !~ /regexp/
% k& ~1 k6 f3 N6 h) V5 c如果 exp 不符合 regexp,则结果为真。
# f# o) @4 H7 p' a
9 z; o+ K& k1 O) l5 o4 c2 ?- c: o5.3 比较的算式当作Patterns. z5 q2 a9 R! v' ~% W, A5 n# c6 r
比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於
5 o, o) g8 k! Q% L) A、小於。下面列出一些比较的pattern:
# {- D) S1 L6 c: o, ox<y 如果 x 小於 y,则结果为真。6 ^' Y' Y/ H3 N2 z4 O+ _. m
x<=y 如果 x 小於、等於 y,则结果为真。! q% Y- @4 A# ?( P% x- V( o
x>y 如果 x 大於 y,则结果为真。1 i2 P8 ~6 _( ~6 r+ S5 X7 w; L
x>=y 如果 x 大於、等於 y,则结果为真。
; H: A. R+ o7 J% [" jx==y 如果 x 等於 y,则结果为真。
3 _3 X, D" ]$ U I$ w0 B' p* Nx!=y 如果 x 不等於 y,则结果为真。
) F: I; ^7 b0 f f% ux~y 如果 x 符合 regular expression y,则结果为真。5 I6 b! V4 H0 \- v: `
x!~y 如果 x 不符合 regular expression y,则结果为真。
a; j2 J9 D4 @* W, F& |& N6 M上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,* M0 p7 _* |) `
否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,
. y0 Z# d' y: p* L1 p8 S. @) i会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同
$ D1 s p# h9 B% p的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视7 j( u4 C) I) I
为长的字串比短的字串大。例如 "10" 比 "9" 小,"abc" 比 "abcd" 小。
# y; _+ s7 |, K: X& V! _3 X7 \" M3 j$ L
) H. H0 t6 \: H9 l. m5.4 使用布林运算的Patterns
4 {! D4 ?, F. U$ t1 R4 Y一个布林(boolean) pattern 是使用布林运算"或"('||'),"及"
5 W3 O/ a) M5 ^7 M/ a5 g('&&'),"反"('!')来组合其它的pattern。% g$ ^( G! z* Z9 d7 B% }
例如:6 Q. ^" M( i. l. P* M) M8 U- L$ k K( e
gawk '/2400/ && /foo/' BBS-list% D+ z8 d% _( T9 n+ S5 ~0 W
gawk '/2400/ || /foo/' BBS-list1 D2 Z8 B; T0 q1 P! n q% s& K
gawk '! /foo/' BBS-list
7 A2 \7 v9 x! |! J3 j7 S" z4 f& c6 ^9 R# R) W
第六章 算式(Expression)作为Actions的叙述
* T; ]8 e, _7 S0 t U N9 T$ g% n算式(Expression) 是gawk程式里面action的基本构成者。3 a9 U- N& H. p+ s9 Z7 I1 Q
% j5 m" I* p" b! {6 ]7 v
6.1 算术运算" r7 G8 c h! Z
gawk 里的算术运算如下所示:
2 s+ B, {6 Y( n. I' `7 Z% Vx+y 加
7 y8 O' ?: D! y' v' Nx-y 减
6 ]1 H5 ]- g% O2 B& n1 c-x 负
; Y2 o# E! O% J2 z0 \2 m+x 正。实际上没有任何影响。+ \7 s' z4 L8 @
x*y 乘
+ d q I* W4 g$ }- @" Rx/y 除. ^9 h9 Y/ B- B& ?# @! `0 P
x%y 求馀数。例如 5%3=2。) Z3 E: ^) c4 n3 ?
x^y) W' N. O1 U7 U: P; h
x**y x 的 y 次方。例如2^3=8。* K% [0 o$ [/ _% u+ b
}. ?2 Q) D! a( h7 O; ~, e6.2 比较算式与布林算式6 x6 Q( j1 |/ J- M8 M8 P
比较算式 (comparison expression) 用来比较字串或数字的关系) T1 {- z! w6 h$ v ~
,运算符号与 C 语言相同。表列如下:
$ i' D( r6 B7 m: Z0 q& h3 ox<y l9 r( c" L$ s/ A! S
x<=y
) O V+ w) o9 X1 C7 e$ y4 Bx>y( {" T @3 j' C. d0 r; N
x>=y6 q1 c0 i, R) R
x==y) E: C m( n9 c# V, w N
x!=y y b2 {' }3 E- M2 s. `9 t
x~y
; C- V2 p9 M! R: B7 k6 v; kx!~y0 J8 G( j. W# t
比较的结果为真(true)则其值是 1。否则其值是 0。, }( f& B7 U2 e- V, p, I3 W
布林算式(boolean expression)有下面三种:
+ k; }6 \5 `) e( x1 q! y$ yboolean1 && boolean2% I& T" |% n' M1 z- Q! o
boolean1 || boolean2
6 z0 n W7 n, F4 b, X! l1 c2 E8 i' [! boolean
" Y$ O0 l6 Y9 z! B& w! w* d! B/ v* L; o8 b9 T
6.3 条件算式(Conditional Expressions)
) q: Y/ N2 D6 r/ w) ]3 T+ d% f一个条件式算式是一种特别的算式,它含有3个运算元。% J" i! `0 d, U4 ^! E" M
条件式算式与C语言的相同:
) X" H: d* `; G# m C U- nselector ? if-true-exp : if-false-exp: L/ c: W4 x9 N& h% u6 @9 E+ j
它有3个子算式。第一个子算式selector 首先会被计算。如果是真,; u8 V7 L% y+ v
则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-6 {* g3 M s X6 r# V. E
exp 会被计算且它的值变成整个算式的值。. t% Q( B8 j3 c0 \( d- V
例如下面的例子会产生x的绝对值:
3 z& Y- v$ V% ~x>0 ? x : -x
+ o+ b, v# w% Y9 p
# J( h, F' C l# D' o2 x) G8 b第七章 Actions里面的控制叙述
& F( Y7 L# M9 M在 gawk 程式里面,控制叙述诸如 if、while 等控制程式执行的流
$ P0 B) n- C0 r' y9 L程。在 gawk 里的控制叙述与 C 的类似。
3 O% @ @) r8 t很多的控制叙述会包括其它的叙述,被包括的叙述称为 body。假( ^" l& ^ Q2 ?' Q; \: h. F
如 body 里面包括一个以上的叙述,必须以大括弧 { } 将这些叙述括起
+ i. M" s. m& p$ b7 X4 l2 G! {6 @- U来,而各个叙述之间需以换行(newline)或分号隔开。
& @; C$ n8 m; I
; o, _" k$ ~9 ]8 U7.1 if 叙述
0 d% k6 p# U9 f" T# u, P' Tif (condition) then-body [else else-body] e/ ]9 V% |! \4 T/ m
如果 condition 为真(true),则执行 then-body,否则执行 else-body。
$ ~3 B* P' q# b5 @& c举一个例子如下:
8 Y0 r& G( |1 w! Uif (x % 2 == 0)3 a: ]6 C% P$ e( { i) ? K
print "x is even"
6 y. L& Z- Q, V" y! h$ Felse
1 z n1 _" D6 ] Aprint "x is odd"$ P6 }7 _& v7 i; W2 ?
" D# Q. i! U9 }3 _7.2 while 叙述
# ~1 U( Y/ ]! y/ y' @1 b8 awhile (condition)
' Y; A' u1 _! B; x- R4 q! f7 b% [6 e7 Hbody, f% V$ J" f" l
while 叙述做的第一件事就是测试 condition。假如 condition 为真则
; {4 u' P. @" M: }: ?6 @执行 body 的叙述。body 的叙述执行完後,会再测试 condition,假如
! [+ j8 `6 n' }0 ?condition 为真,则 body 会再度被执行。这个过程会一直被重复直到
& s1 M( e: @; K, K5 fcondition 不再是真。如果 condition 第一次测试就是伪(false),则0 a% V2 n0 Q) A) o
body 从没有被执行。) u2 S: p- V. J. y, S& H
下面的例子会印出每个输入记录(record)的前三个栏位。3 D: @4 u; a9 N# f
gawk '{ i=1- a2 V9 k# u1 r! }+ ~
while (i <= 3) {" W* A' ]6 @- J5 Z* |
print $i) `# X3 G& J S3 h9 {5 Q1 [
i++
! e9 Z! `3 o" \ J) y' @6 w1 }}
8 C" [; u/ A' `5 P4 d4 H4 H2 t}' _4 `8 @0 B! r; P. v% T
$ B4 z5 e5 e' b6 t
7.3 do-while 叙述
/ j% v% Z7 t/ {+ {$ P; Qdo
$ C4 [* w1 R" o! ~# n0 \4 m/ Pbody# ^6 p5 S7 a9 \, B0 e2 h
while (condition)- [& M9 R3 i+ j
这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。5 A9 H! g! ]& ^" W
即使开始时 condition 是伪,body 也会被执行一次。5 Y! w \# j7 n. @6 m1 N* n
下面的例子会印出每个输入记录十次。
# L- B% d. H9 [/ ugawk '{ i= 1. e5 T7 H8 l% V8 G$ v, A9 ?
do {
1 d: I* x# l% kprint $01 R, X2 f1 C+ \, I
i++
1 h& s7 D" ^ a} while (i <= 10)
~6 K* v6 {4 o}'
* [2 @- j D1 ], U" M& I2 q/ x
, V% @5 t% {8 _0 E: x: H7.4 for 叙述5 H8 w8 }6 n. ^, D, c5 }7 u) C
for (initialization; condition; increment)1 s1 \$ D2 _+ x2 E. @5 `! o
body
# o- H, c! K+ y3 [. a此叙述开始时会执行initialization,然後只要 condition是真,它! T U: V7 D3 ^3 b
会重复执行body与做increment 。
) C, [" W) P2 ~5 s$ K. X下面的例子会印出每个输入记录的前三个栏位。2 c) u% P+ _& W- X z7 `
gawk '{ for (i=1; i<=3; i++)
/ ~& N! I# y; E. zprint $i
9 h$ u7 b; e5 r# h}'
2 y9 v2 X5 a# g& ^
7 z1 l& m% K6 g7 I' ^" A7.5 break 叙述+ }( ?/ K: z8 Q+ D: O
break 叙述会跳出包含它的 for、while、do-while 回圈的最内层。
2 D8 b/ L% i0 _4 F9 r+ Q下面的例子会找出任何整数的最小除数,它也会判断是否为质数。5 Y3 d6 @( C" I& y+ F0 F7 n. y
gawk '# find smallest divisor of num
$ ^% f+ A3 [: X# S{ num=$1
& P7 h0 J5 g( C" ^( ]for (div=2; div*div <=num; div++)) s. L) p( ~) V; O8 n" B- n# H" l2 `
if (num % div == 0)
4 V" f5 y. X! K* K% [break6 Z5 G* f0 l8 e' R% ?# p
if (num % div == 0)
, \$ P N4 l1 q5 j9 zprintf "Smallest divisor of %d is %d\n", num, div
8 ?4 Q( Q9 R' x; I+ B8 C E. kelse
* v5 P: G. P# Lprintf "%d is prime\n", num }'9 d/ S0 ?" b' L. P8 u. B4 I
% V' D* A1 f& X5 k& s( q% k
7.6 continue 叙述2 w2 j# a" t9 {
continue 叙述使用於 for、while、do-while 回圈内部,它会跳" K2 V% L! b7 t2 x$ B
过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。; I5 H5 y T! X! i: S. w
下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。
" S8 f; n; a$ r! [gawk 'BEGIN {' g! V& E# c% E! Y8 b
for (x=0; x<=20; x++) {/ p" H" u1 x" ~% W! Q; R5 M
if (x==5)
: [( f3 Z; U4 L; H. J: ^4 }continue _$ n. H4 r1 [2 U0 G, }
printf ("%d",x)2 a1 s& \& U5 d. @9 Y2 K1 k2 W
}
0 m6 J! E# A5 {9 L- O% {. tprint ""; T ~( }% r0 n- O
}'3 F. ]# ]! W5 R5 d
0 j9 G5 G- ^- B7.7 next 叙述、next file 叙述、exit 叙述 |' i K! e9 H4 {8 S" l1 j
next 叙述强迫 gawk 立刻停止处理目前的记录(record)而继续下一% D( ^8 S9 U6 s/ F) C) K
个记录。0 p8 n7 `1 v4 R+ g: {
next file 叙述类似 next。然而,它强迫 gawk 立刻停止处理目前
. h1 G" n1 V( `( B的资料档。8 i% D4 b2 _. o# b
exit 叙述会使得 gawk 程式停止执行而跳出。然而,如果 END 出现
- w+ v# n* W: }+ w,它会去执行 END 的 actions。5 P* B. l; ?' ~2 ]/ S. o+ R3 G
I9 L+ O- {1 o" ^+ B第八章 内建函式(Built-in Functions)$ w3 [* i G' Z. S
内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建
# R( i" I2 ], {函式。
3 a5 m' x3 i5 O; P$ Q0 ^, F) n$ h& g7 N
8.1 数值方面的内建函式
: ]- [2 O0 K9 K" Bint(x) 求出 x 的整数部份,朝向 0 的方向做舍去。例如:int(3.9)
! @; X+ D4 r7 J, z7 Z. Y1 U$ q! T8 H; v是 3,int(-3.9) 是 -3。
1 z9 ?) G7 M. J [ t1 d U/ Jsqrt(x) 求出 x 正的平方根值。例 sqrt(4)=29 z% S/ m8 Y2 M3 V2 e, W
exp(x) 求出 x 的次方。例 exp(2) 即是求 e*e 。5 D/ b1 w& B& ^4 \2 P
log(x) 求出 x 的自然对数。: |) \" d7 y0 F& X2 |! n2 \
sin(x) 求出 x 的 sine 值,x 是弪度量。$ [" T' V- g" \) f7 e1 c
cos(x) 求出 x 的 cosine 值,x 是弪度量。; z# u4 P# l8 I' h/ T @! R
atan2(y,x) 求 y/x 的 arctangent 值,所求出的值其单位是弪度量。
- r: n! H) I+ B) U; }5 s) Krand() 得出一个乱数值。此乱数值平均分布在 0 和 1 之间。这个
4 D a$ t& N, q# Y3 R值不会是 0,也不会是 1。
- r4 C9 v1 `+ Z( L! X, ]每次执行 gawk,rand 开始产生数字从相同点或 seed。
- `# `5 }" U- G' o" n4 P) Osrand(x) 设定产生乱数的开始点或 seed 为 x。如果在第二次你设5 q! d! Q/ k P7 f# b
定相同的 seed 值,你将再度得到相同序列的乱数值。
) P! M8 b+ H- F) I7 @5 J如果省略引数 x,例如 srand(),则现在的日期、时间会
1 d/ x5 g/ ?5 }! V9 ~被当成 seed。这个方法可使得乱数值是真正不可预测的。. s' _* H+ ?/ J, z
srand 的传回值(return value)是前次所设定的 seed 值。
z. n& [9 y% b$ T2 B# J6 A* L0 P
! r7 s4 E- a& ], U8.2 字串方面的内建函式3 D4 ~, H/ m% t4 h! t/ N* c' w
index(in, find)
* v4 y# \. U+ f! R* g它会在字串 in 里面,寻找字串 find 第一次出现的地方,传回值是
4 j) x; r5 p& m9 s字串 find 出现在字串 in 里面的位置。如果在字串 in 里面找不到字
% \1 t7 o% D# ^ I" `6 P3 I串 find,则传回值为 0。& m0 [4 c6 C, g9 D. _, d
例如:
6 l3 D# e p- ~6 ]" k7 {print index("peanut","an")
- i. [' U! A1 m J0 {会印出 3。3 |- R: @ V+ \- I; N
length(string); m& g9 M$ H4 ?% T9 M5 C1 x0 z
求出 string 有几个字元。
3 Q9 D7 u4 S- k4 h' O例如:" y$ o B9 k6 b
length("abcde")
& o0 g4 u% u2 I是 5。
& k" p$ I' ^4 H/ i7 x$ r, Omatch(string,regexp)
! M2 V/ ~- C$ H" _# A0 K8 Omatch 函式会在字串 string 里面,寻找符合 regexp 的最长、最靠
3 q8 S/ Z, ` f' z: d: {& o左边的子字串。传回值是 regexp 在 string 的开始位置,即 index$ q1 n$ g' W) d2 z& c. X. V
值。
W+ X4 o# |+ \; W: ], `, @" Fmatch 函式会设定内在变数 RSTART 等於 index,它也会设定内在变
, \" {: q0 [6 l }+ d" D' @2 K" r5 d数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为4 a. M) h% X& x' Y; t$ t2 ^$ b
0、RLENGTH 为 -1。
9 g) s9 R! d& l7 [- g6 Rsprintf(format,expression1,...)
4 w$ m" C" U* B8 ^% n3 x2 N8 _举 printf 类似,但是 sprintf 并不印出,而是传回字串。; [% P8 P0 j8 a9 @" B$ P
例如:* X& C; T: t/ W; e
sprintf("pi = %.2f (approx.)',22/7)
7 v1 z' s9 [) {% H$ R4 m8 p传回的字串为"pi = 3.14 (approx.)"
5 p* s& ]7 o* I2 t b9 \sub(regexp, replacement,target)4 ]/ Q1 R0 b9 k
在字串 target 里面,寻找符合 regexp 的最长、最靠左边的地方,
# k O; ~! f( a! b' t以字串 replacement 代替最左边的 regexp。
9 l5 r5 |6 O. J1 n0 y/ D例如:/ Y. z; W+ U# o
str = "water, water, everywhere"7 k, a# B' e$ T# m% v
sub(/at/, "ith",str)
# D" R5 d% l- ~- ~, M4 `结果字串str会变成/ j$ C( @. F, P( ]# [2 v* E
"wither, water, everywhere"
- M. Y: }6 V* i. p5 [, {5 v9 \gsub(regexp, replacement, target)
" G9 ~+ I$ J4 @6 F2 Fgsub 与前面的 sub 类似。在字串 target 里面,寻找符合 regexp 的
. Y& a8 d# w* u所有地方,以字串 replacement 代替所有的 regexp。& h. v4 O! j1 l# h
例如:
2 C b9 L' Z- [7 qstr="water, water, everywhere"
3 n* i. U& ` ]gsub(/at/, "ith",str)
* l4 N5 m6 S3 q: J结果字串str会变成
- }' X+ U' B4 X$ v0 c0 t$ \8 t3 x'wither, wither, everywhere"
% H0 c) M8 x% R' [: b, i0 {7 d) nsubstr(string, start, length)
9 x) V. l) @! B5 ]* ^, K5 f传回字串 string 的子字串,这个子字串的长度为 length 个字元,
2 d8 p1 V# s3 X! V: J. c) z. r2 t从第 start 个位置开始。
) T$ s4 q% c0 z5 v4 ], U6 @例如:
3 k5 w6 @- N/ vsubstr("washington",5,3)4 @% z) ]0 J9 D$ [3 L
传回值为"ing"3 S8 T/ ]& M" @1 ^
如果 length 没有出现,则传回的子字串是从第 start 个位置开始0 |9 }6 R n' X' x8 r$ E& n
至结束。+ G1 a/ {& S9 w3 c/ N( J% e' e/ z
例如:
! J1 o& x0 B/ _' [7 v$ A. {substr("washington",5)
& b- r, V$ R e- I6 X传回值为"ington"
! E; k+ f2 ^& b: htolower(string)
! U" {9 t7 S. E7 \将字串string的大写字母改为小写字母。
% T. H6 n: k6 m9 O6 P例如:- _5 K7 R& r4 q6 b
tolower("MiXeD cAsE 123")6 A, B7 J- Q$ @% L3 _- G/ W9 j7 Q% I
传回值为"mixed case 123"
3 B# P6 _& \: Q7 Z3 wtoupper(string)0 i8 N; F' T7 @! B0 f( a$ c% h
将字串string的小写字母改为大写字母。
- ?: E+ p! C$ S4 a例如:
1 L0 G# L/ g, {) \toupper("MiXeD cAsE 123")/ u, Q& |9 n% m1 d' |
传回值为"MIXED CASE 123"
% h# k; D7 d3 S+ l6 C" k7 S3 B' M( E; ^ N# B8 j* I' I
8.3 输入输出的内建函式
7 `* Z l; w+ mclose(filename)
( `8 G) i* ]. I) l$ M9 l" S, C# M将输入或输出的档案 filename 关闭。8 j7 w* W3 @7 ]0 z, W
system(command)
$ q: O; X# d3 |) z' B4 a2 a( D此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk' ? C' K6 _+ s1 o0 N
程式。
) Q% y' v3 a% p' S3 q) N例如:
; K1 `: ]' F1 o+ l4 j1 p4 iBEGIN {system("ls")}! d2 u5 T- M% j6 Z# c
6 s% \4 V" _1 x第九章 使用者定义的函式(User-defined Functions)3 B+ k6 ]- j9 I' w( j( ?7 ]
复杂的 gawk 程式常常可以使用自己定义的函式来简化。呼叫使用! Y- ? D+ b" k$ \
者定义的函式与呼叫内建函式的方法一样。1 h: B" d! N+ m7 U2 C: b, G
3 q% f" b' a' b
9.1 函式定义的格式( c! U3 m, i5 k
函式的定义可以放在 gawk 程式的任何地方。, R5 O" n( T% ]( t- \' f6 u0 W
一个使用者定义的函式其格式如下:* K0 g* d' N% S2 A) v
function name (parameter-list) {" a& I" b, |! \# r
body-of-function, N# D H% ?# U+ r0 K: h' v p. p7 a
}; O( _- ]: L5 g- \) j" Y
name 是所定义的函式之名称。一个正确的函式名称可包括一序列的字
% K" |5 b6 e) _' v4 D母、数字、下标线 (underscores),但是不可用数字做开头。
4 J8 T/ k. G1 i# u8 Aparameter-list 是列出函式的全部引数(argument),各个引数之
1 R% W! Q6 C- E4 P间以逗点隔开。
4 q% C+ u$ z, b* S9 ibody-of-function 包含 gawk 的叙述 (statement)。它是函式定义8 `& r% V. s! ^3 G- G5 ]9 `# o8 i
里最重要的部份,它决定函式实际要做何种事。$ `/ S, v9 t! K' n+ ?0 K
: H) y T% Z% G; d ^0 \( H; J
9.2 函式定义的例子
3 N4 C) V' a' Y; @1 [" r下面这个例子,会将每个记录的第一个栏位之值的平方与第二个- {8 r) y6 r' A0 t+ T
栏位之值的平方加起来。* @3 m* q; K/ l; ~' i
{print "sum =",SquareSum($1,$2)}/ I# O5 V% X ?0 K9 x2 u1 D
function SquareSum(x,y) {
0 L. |. Q; ^! L, Jsum=x*x+y*y# W4 o% C$ e! e
return sum7 b( i$ j Z2 S @/ L
}( C: O: [; S# s6 S L& H* V' P4 v Z
/ j3 s. z2 i( N- z. @
第十章 □例
, Q' H) [8 [2 y# B5 }) R" Z- D这里将列出 gawk 程式的一些例子。
3 f4 |9 h' b% V0 i. ?# Ggawk '{if (NF > max) max = NF}( I9 G8 P! A3 ~! M: H5 M4 C; I# C
END {print max}'- y- x& Q& }- B
此程式会印出所有输入行之中,栏位的最大个数。. v$ G/ _7 p |5 [. u$ b
gawk 'length($0) > 80'( D3 @( Q. \1 O q4 \& a6 d g
此程式会印出一行超过 80 个字元的每一行。此处只有 pattern 被# y3 P& } U* O0 b! v7 A, `7 n2 }7 s3 O
列出,action 是采用内定的 print。
4 S+ {+ C. {/ B" H( n9 y# j4 Z, |9 xgawk 'NF > 0'3 a. m' g: A. ^" k* g. i- y! D
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
0 c/ @' [8 G8 x1 q单的方法,将一个档案里的所有空白行删除。
9 H4 p9 n/ O/ Y7 [: A2 }" Tgawk '{if (NF > 0) print}'
5 m7 _) Y& I3 ]7 ^2 C9 f& V: _/ a对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
: l; U! ]. i9 w+ d4 b, l) e单的方法,将一个档案里的所有空白行删除。/ G6 t/ U l9 j8 y
gawk 'BEGIN {for (i = 1; i <= 7; i++): q, `2 A0 v3 b
print int(101 * rand())}'
+ T! u1 o8 j {( K- {! P: G7 T此程式会印出□围是 0 到 100 之间的 7 个乱数值。
# }+ ]) i. ^% g3 V/ [$ Dls -l files | gawk '{x += $4}; END {print "total bytes: " x}'
3 E$ O: N9 x: O# V# V1 N `此程式会印出所有指定的档案之bytes数目的总和。
, K7 H2 D7 E% d1 C5 r7 j O3 [expand file | gawk '{if (x < length()) x = length()}
& c6 H1 p/ }2 i+ h/ \END {print "maximum line length is " x}'/ H1 d6 G) O1 ?' P/ Q6 a$ R
此程式会将指定档案里最长一行的长度印出。expand 会将 tab 改
7 j: {" Y( a& l5 q成 space,所以是用实际的右边界来做长度的比较。
/ G, A9 U& z/ h$ S! xgawk 'BEGIN {FS = ":"}
9 w5 F1 p6 X8 G- w$ e Z{print $1 | "sort"}' /etc/passwd" o' i2 X" z9 c5 S( }5 R
此程式会将所有使用者的login名称,依照字母的顺序印出。
8 ]- e. |* U3 x0 Kgawk '{nlines++}
' M5 j3 S& {3 p' {. [+ a! lEND {print nlines}'4 z) ^% x$ m e7 o, D
此程式会将一个档案的总行数印出。
0 w8 D# z( Q6 z; W7 Wgawk 'END {print NR}'
" N& b' H5 {; A此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk
) @0 h+ H4 Z$ I# r6 ?. `! ?来做。# B8 }; b+ I* d0 @7 X
gawk '{print NR,$0}'
; P' |& J& ]4 x6 ]# C此程式印出档案的内容时,会在每行的最前面印出行号,它的功8 n d2 \5 G$ H8 @7 E: W: P
能与 'cat -n' 类似。, z* b: c8 ?0 C# @3 O6 v
6 k" B1 Z# j0 |8 B
第十一章 结论; Y5 G+ G5 n; U* D3 r! T% S% q. O
gawk 对於资料的处理具有很强的功能。它能够以很短的程式完成
# ?4 W" \1 a: h: F1 e想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件 b8 G9 \; ~( E$ I d
工作,以 gawk 程式来写会比用其它程式语言来写短很多。, ^' S7 s4 U$ F1 c
gawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使& H. x! D' z+ v. e m
用。 |
|