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