作者:cicc 2005-02-03 15:53:59 來(lái)自:Linux先生 |
|
??? a w k是一種程序語(yǔ)言,對(duì)文檔資料的處理具有很強(qiáng)的功能。awk 名稱是由它三個(gè)最初設(shè)計(jì)者的姓氏的第一個(gè)字母而命名的: Alfred V. Aho、Peter J. We i n b e rg e r、Brian W. Kernighan。 ???a w k最初在1 9 7 7年完成。1 9 8 5年發(fā)表了一個(gè)新版本的a w k,它的功能比舊版本增強(qiáng)了不少。a w k能夠用很短的程序?qū)ξ臋n里的資料做修改、比較、提取、打印等處理。如果使用C 或P a s c a l等語(yǔ)言編寫(xiě)程序完成上述的任務(wù)會(huì)十分不方便而且很花費(fèi)時(shí)間,所寫(xiě)的程序也會(huì)很大。 ???a w k不僅僅是一個(gè)編程語(yǔ)言,它還是L i n u x系統(tǒng)管理員和程序員的一個(gè)不可缺少的工具。a w k語(yǔ)言本身十分好學(xué),易于掌握,并且特別的靈活。 ???gawk 是G N U計(jì)劃下所做的a w k,gawk 最初在1 9 8 6年完成,之后不斷地被改進(jìn)、更新。gawk 包含awk 的所有功能。
6.1 gawk的主要功能
???gawk 的主要功能是針對(duì)文件的每一行( l i n e ),也就是每一條記錄,搜尋指定的格式。當(dāng)某一行符合指定的格式時(shí),gawk 就會(huì)在此行執(zhí)行被指定的動(dòng)作。gawk 依此方式自動(dòng)處理輸入文件的每一行直到輸入文件檔案結(jié)束。 ???g a w k經(jīng)常用在如下的幾個(gè)方面: ???? 根據(jù)要求選擇文件的某幾行,幾列或部分字段以供顯示輸出。 ???? 分析文檔中的某一個(gè)字出現(xiàn)的頻率、位置等。 ???? 根據(jù)某一個(gè)文檔的信息準(zhǔn)備格式化輸出。 ???? 以一個(gè)功能十分強(qiáng)大的方式過(guò)濾輸出文檔。 ???? 根據(jù)文檔中的數(shù)值進(jìn)行計(jì)算。
6.2 如何執(zhí)行g(shù)awk程序
???基本上有兩種方法可以執(zhí)行g(shù) a w k程序。 ???如果gawk 程序很短,則可以將gawk 直接寫(xiě)在命令行,如下所示: ??????gawk 'program' input-file1 input-file2 ... ??? ?? 其中program 包括一些pattern 和a c t i o n。 ???如果gawk 程序較長(zhǎng),較為方便的做法是將gawk 程序存在一個(gè)文件中,gawk 的格式如下所示: ???gawk -f program-file input-file1 input-file2 ... ???gawk 程序的文件不止一個(gè)時(shí),執(zhí)行g(shù)awk 的格式如下所示: ??? ???gawk -f program-file1 -f program-file2 ... input-file1 input-file2 ...
6.3 文件、記錄和字段
???一般情況下,g a w k可以處理文件中的數(shù)值數(shù)據(jù),但也可以處理字符串信息。如果數(shù)據(jù)沒(méi)有存儲(chǔ)在文件中,可以通過(guò)管道命令和其他的重定向方法給g a w k提供輸入。當(dāng)然, g a w k只能處理文本文件(A S C I I碼文件)。?電話號(hào)碼本就是一個(gè)g a w k可以處理的文件的簡(jiǎn)單例子。電話號(hào)碼本由很多條目組成,每一個(gè)條目都有同樣的格式:姓、名、地址、電話號(hào)碼。每一個(gè)條目都是按字母順序排列。在g a w k中,每一個(gè)這樣的條目叫做一個(gè)記錄。它是一個(gè)完整的數(shù)據(jù)的集合。例如,電話號(hào)碼本中的Smith John這個(gè)條目,包括他的地址和電話號(hào)碼,就是一條記錄。 ???記錄中的每一項(xiàng)叫做一個(gè)字段。在g a w k中,字段是最基本的單位。多個(gè)記錄的集合組成了一個(gè)文件。 ???大多數(shù)情況下,字段之間由一個(gè)特殊的字符分開(kāi),像空格、TA B、分號(hào)等。這些字符叫做字段分隔符。請(qǐng)看下面這個(gè)/ e t c / p a s s w d文件: t p a r k e r ; t 3 6 s 6 2 h s h ; 5 0 1 ; 1 0 1 ; Tim Parker;/home/tparker;/bin/bash etreijs;2ys639dj3h;502;101;Ed Tr e i j s ; / h o m e / e t r e i j s ; / b i n / t c s h y c h o w ; 1 h 2 7 s j ; 5 0 3 ; 1 0 1 ; Yvonne Chow;/home/ychow;/bin/bash ???你可以看出/ e t c / p a s s w d文件使用分號(hào)作為字段分隔符。/ e t c / p a s s w d文件中的每一行都包括七個(gè)字段:用戶名;口令;用戶I D;工作組I D;注釋; h o m e目錄;啟始的外殼。如果你想要查找第六個(gè)字段,只需數(shù)過(guò)五個(gè)分號(hào)即可。 ???但考慮到以下電話號(hào)碼本的例子,你就會(huì)發(fā)現(xiàn)一些問(wèn)題: Smith John 13 Wilson St. 555-1283 Smith John 2736 Artside Dr Apt 123 555-2736 Smith John 125 Westmount Cr 555-1726 ???雖然我們能夠分辨出每個(gè)記錄包括四個(gè)字段,但g a w k卻無(wú)能為力。電話號(hào)碼本使用空格作為分隔符,所以g a w k認(rèn)為S m i t h是第一個(gè)字段, John 是第二個(gè)字段,1 3是第三個(gè)字段,依次類推。就g a w k而言,如果用空格作為字段分隔符的話,則第一個(gè)記錄有六個(gè)字段,而第二個(gè)記錄有八個(gè)字段。 ???所以,我們必須找出一個(gè)更好的字段分隔符。例如,像下面一樣使用斜杠作為字段分隔符: Smith/John/13 Wilson St./555-1283 Smith/John/2736 Artside Dr/Apt/123/555-2736 Smith/John/125 Westmount Cr/555-1726 ???如果你沒(méi)有指定其他的字符作為字段分隔符,那么g a w k將缺省地使用空格或TA B作為字段分隔符。
6.4 模式和動(dòng)作
???在g a w k語(yǔ)言中每一個(gè)命令都由兩部分組成:一個(gè)模式( p a t t e r n)和一個(gè)相應(yīng)的動(dòng)作(a c t i o n)。只要模式符合,g a w k就會(huì)執(zhí)行相應(yīng)的動(dòng)作。其中模式部分用兩個(gè)斜杠括起來(lái),而動(dòng)作部分用一對(duì)花括號(hào)括起來(lái)。例如: / p a t t e r n 1 / { a c t i o n 1 } / p a t t e r n 2 / { a c t i o n 2 } / p a t t e r n 3 / { a c t i o n 3 } ???所有的g a w k程序都是由這樣的一對(duì)對(duì)的模式和動(dòng)作組成的。其中模式或動(dòng)作都能夠被省略,但是兩個(gè)不能同時(shí)被省略。如果模式被省略,則對(duì)于作為輸入的文件里面的每一行,動(dòng)作都會(huì)被執(zhí)行。如果動(dòng)作被省略,則缺省的動(dòng)作被執(zhí)行,既顯示出所有符合模式的輸入行而不做任何的改動(dòng)。 ???下面是一個(gè)簡(jiǎn)單的例子,因?yàn)間awk 程序很短,所以將gawk 程序直接寫(xiě)在外殼命令行: gawk '/tparker/' /etc/passwd
????此程序在上面提到的/ e t c / p a s s w d文件中尋找符合t p a r k e r模式的記錄并顯示(此例中沒(méi)有動(dòng)作,所以缺省的動(dòng)作被執(zhí)行)。 ???讓我們?cè)倏匆粋€(gè)例子: ???gawk '/UNIX/{print $2}' file2.data ???此命令將逐行查找f i l e 2 . d a t a文件中包含U N I X的記錄,并打印這些記錄的第二個(gè)字段。你也可以在一個(gè)命令中使用多個(gè)模式和動(dòng)作對(duì),例如: gawk '/scandal/{print $1} /rumor/{print $2}' gossip_file ???此命令搜索文件g o s s i p _ f i l e中包括s c a n d a l的記錄,并打印第一個(gè)字段。然后再?gòu)念^搜索g o s s i p _ f i l e中包括r u m o r的記錄,并打印第二個(gè)字段。
6.5 比較運(yùn)算和數(shù)值運(yùn)算
???g a w k有很多比較運(yùn)算符,下面列出重要的幾個(gè): = = 相等 ! = 不相等 > 大于 < 小于 > = 大于等于 < = 小于等于 ???例如:??gawk '$4 > 100' testfile ???將會(huì)顯示文件testfile 中那些第四個(gè)字段大于1 0 0的記錄。 ???下表列出了g a w k中基本的數(shù)值運(yùn)算符。 ???運(yùn)算符說(shuō)明示例 ???+ 加法運(yùn)算2+6 ???- 減法運(yùn)算6-3 ???* 乘法運(yùn)算2*5 ???/ 除法運(yùn)算8/4 ???^ 乘方運(yùn)算3^2 (=9) ???% 求余數(shù)9%4 (=1) ???例如:{print $3/2} 顯示第三個(gè)字段被2除的結(jié)果。 ???在g a w k中,運(yùn)算符的優(yōu)先權(quán)和一般的數(shù)學(xué)運(yùn)算的優(yōu)先權(quán)一樣。例如:{print $1+$2*$3} ???顯示第二個(gè)字段和第三個(gè)字段相乘,然后和第一個(gè)字段相加的結(jié)果。 ???你也可以用括號(hào)改變優(yōu)先次序。例如: ???{print ($1+$2)*$3} ???顯示第一個(gè)字段和第二個(gè)字段相加,然后和第三個(gè)字段相乘的結(jié)果。
6.6 內(nèi)部函數(shù)
g a w k中有各種的內(nèi)部函數(shù),現(xiàn)在介紹如下:?
6.6.1 隨機(jī)數(shù)和數(shù)學(xué)函數(shù)
sqrt(x) 求x 的平方根 sin(x) 求x 的正弦函數(shù) cos(x) 求x 的余弦函數(shù) a t a n 2 ( x,y) 求x / y的余切函數(shù) log(x) 求x 的自然對(duì)數(shù) exp(x) 求x 的e 次方 int(x) 求x 的整數(shù)部分 rand() 求0 和1之間的隨機(jī)數(shù) srand(x) 將x 設(shè)置為r a n d ( )的種子數(shù)
6.6.2 字符串的內(nèi)部函數(shù)
? i n d e x ( i n,find) 在字符串in 中尋找字符串find 第一次出現(xiàn)的地方,返回值是字符串find 出現(xiàn)在字符串in 里面的位置。如果在字符串in 里面找不到字符串f i n d,則返回值為0。 例如: print index("peanut"," a n " ) 顯示結(jié)果3。 ? length(string) 求出string 有幾個(gè)字符。 例如: l e n g t h ( " a b c d e " ) 顯示結(jié)果5。 ? m a t c h ( s t r i n g,r e g e x p ) 在字符串string 中尋找符合regexp 的最長(zhǎng)、最靠左邊的子字符串。返回值是regexp 在string 的開(kāi)始位置,即i n d e x值。match 函數(shù)將會(huì)設(shè)置系統(tǒng)變量R S TA RT 等于i n d e x的值,系統(tǒng)變量RLENGTH 等于符合的字符個(gè)數(shù)。如果不符合,則會(huì)設(shè)置R S TA RT 為0、RLENGTH 為- 1。 ? s p r i n t f ( f o r m a t,e x p r e s s i o n 1,. . . ) 和printf 類似,但是sprintf 并不顯示,而是返回字符串。例如: sprintf("pi = %.2f (approx.)",2 2 / 7 ) 返回的字符串為pi = 3.14 (approx.) ? s u b ( r e g e x p,r e p l a c e m e n t,t a rg e t ) 在字符串t a rget 中尋找符合regexp 的最長(zhǎng)、最靠左的地方,以字串replacement 代替最左邊的r e g e x p。 例如: str = "water,w a t e r,e v e r y w h e r e " s u b ( / a t /, " i t h ",s t r ) 結(jié)果字符串s t r會(huì)變成 w i t h e r,w a t e r,e v e r y w h e r e ? g s u b ( r e g e x p,r e p l a c e m e n t,t a rget) 與前面的s u b類似。在字符串t a rget 中尋找符合r e g e x p的所有地方,以字符串replacement 代替所有的r e g e x p。例如: s t r = " w a t e r,w a t e r,e v e r y w h e r e "g s u b ( / a t /, " i t h ",s t r ) 結(jié)果字符串s t r會(huì)變成 w i t h e r,w i t h e r,e v e r y w h e r e ? s u b s t r ( s t r i n g,s t a r t,length) 返回字符串string 的子字符串,這個(gè)子字符串的長(zhǎng)度為l e n g t h,從第start 個(gè)位置開(kāi)始。例如: s u b s t r ( " w a s h i n g t o n ",5,3 )返回值為i n g 如果沒(méi)有l(wèi)ength ,則返回的子字符串是從第start 個(gè)位置開(kāi)始至結(jié)束。 例如: s u b s t r ( " w a s h i n g t o n ",5 ) 返回值為i n g t o n。 ? tolower(string) 將字符串s t r i n g的大寫(xiě)字母改為小寫(xiě)字母。 例如: tolower("MiXeD cAsE 123") 返回值為mixed case 123。 ? toupper(string) 將字符串s t r i n g的小寫(xiě)字母改為大寫(xiě)字母。 例如: toupper("MiXeD cAsE 123") 返回值為MIXED CASE 123。
6.6.3 輸入輸出的內(nèi)部函數(shù)
? close(filename) 將輸入或輸出的文件filename 關(guān)閉。 ? system(command) 此函數(shù)允許用戶執(zhí)行操作系統(tǒng)的指令,執(zhí)行完畢后將回到g a w k程序。例如: BEGIN {system("ls")}
6.7 字符串和數(shù)字
字符串就是一連串的字符,它可以被g a w k逐字地翻譯。字符串用雙引號(hào)括起來(lái)。數(shù)字不能用雙引號(hào)括起來(lái),并且g a w k將它當(dāng)作一個(gè)數(shù)值。例如: gawk '$1 != "Tim" {print}' testfile 此命令將顯示第一個(gè)字段和Ti m不相同的所有記錄。如果命令中Ti m兩邊不用雙引號(hào),g a w k將不能正確執(zhí)行。再如: gawk '$1 == "50" {print}' testfile ???此命令將顯示所有第一個(gè)字段和5 0這個(gè)字符串相同的記錄。g a w k不管第一字段中的數(shù)值的大小,而只是逐字地比較。這時(shí),字符串5 0和數(shù)值5 0并不相等。
6.8 格式化輸出
???我們可以讓動(dòng)作顯示一些比較復(fù)雜的結(jié)果。例如: gawk '$1 != "Tim" {print $1,$ 5,$ 6,$2}' testfile 將顯示t e s t f i l e文件中所有第一個(gè)字段和Ti m不相同的記錄的第一、第五、第六和第二個(gè)字段。進(jìn)一步,你可以在p r i n t動(dòng)作中加入字符串,例如: gawk '$1 != "Tim" {print "The entry for ",$ 1,"is not Tim. ",$2}' testfile ???p r i n t動(dòng)作的每一部分用逗號(hào)隔開(kāi)。 ???借用C語(yǔ)言的格式化輸出指令,可以讓g a w k的輸出形式更為多樣。這時(shí),應(yīng)該用p r i n t f而不是p r i n t。例如: {printf "%5s likes this language\n",$ 2 } p r i n t f中的%5s 部分告訴gawk 如何格式化輸出字符串,也就是輸出5個(gè)字符長(zhǎng)。它的值由printf 的最后部分指出,在此是第二個(gè)字段。\ n是回車換行符。如果第二個(gè)字段中存儲(chǔ)的是人名,則輸出結(jié)果大致如下: Tim likes this language G e o ff likes this language Mike likes this language Joe likes this language ???gawk 語(yǔ)言支持的其他格式控制符號(hào)如下: ? c 如果是字符串,則顯示第一個(gè)字符;如果是整數(shù),則將數(shù)字以ASCII 字符的形式顯示。 例如: printf “% c”,6 5 結(jié)果將顯示字母A。 ? d 顯示十進(jìn)制的整數(shù)。 ? i 顯示十進(jìn)制的整數(shù)。 ? e 將浮點(diǎn)數(shù)以科學(xué)記數(shù)法的形式顯示。 例如: print “$ 4 . 3 e”,1 9 5 0 結(jié)果將顯示1 . 9 5 0 e + 0 3。 ? f 將數(shù)字以浮點(diǎn)的形式顯示。 ? g 將數(shù)字以科學(xué)記數(shù)法的形式或浮點(diǎn)的形式顯示。數(shù)字的絕對(duì)值如果大于等于0 . 0 0 0 1則 以浮點(diǎn)的形式顯示,否則以科學(xué)記數(shù)法的形式顯示。 ? o 顯示無(wú)符號(hào)的八進(jìn)制整數(shù)。 ? s 顯示一個(gè)字符串。 ? x 顯示無(wú)符號(hào)的十六進(jìn)制整數(shù)。1 0至1 5以a至f表示。 ? X 顯示無(wú)符號(hào)的十六進(jìn)制整數(shù)。1 0至1 5以A至F表示。 ? % 它并不是真正的格式控制字符,% %將顯示%。 當(dāng)你使用這些格式控制字符時(shí),你可以在控制字符前給出數(shù)字,以表示你將用的幾位或幾個(gè)字符。例如,6 d表示一個(gè)整數(shù)有6位。再請(qǐng)看下面的例子: {printf "%5s works for %5s and earns %2d an hour",$ 1,$ 2,$ 3 } 將會(huì)產(chǎn)生類似如下的輸出: Joe works for Mike and earns 12 an hour 當(dāng)處理數(shù)據(jù)時(shí),你可以指定數(shù)據(jù)的精確位數(shù) {printf "%5s earns $%.2f an hour",$ 3,$ 6 } 其輸出將類似于: Joe earns $12.17 an hour
你也可以使用一些換碼控制符格式化整行的輸出。之所以叫做換碼控制符,是因?yàn)間 a w k對(duì)這些符號(hào)有特殊的解釋。下面列出常用的換碼控制符:
\a 警告或響鈴字符。 \b 后退一格。 \f 換頁(yè)。 \n 換行。 \r 回車。 \t Ta b。 \v 垂直的t a b。
6.9 改變字段分隔符
???在g a w k中,缺省的字段分隔符一般是空格符或TA B。但你可以在命令行使用- F選項(xiàng)改變字符分隔符,只需在- F后面跟著你想用的分隔符即可。 gawk -F" ;"'/tparker/{print}' /etc/passwd ???在此例中,你將字符分隔符設(shè)置成分號(hào)。注意: - F必須是大寫(xiě)的,而且必須在第一個(gè)引號(hào)之前。
6.10 元字符
g a w k語(yǔ)言在格式匹配時(shí)有其特殊的規(guī)則。例如, c a t能夠和記錄中任何位置有這三個(gè)字符的字段匹配。但有時(shí)你需要一些更為特殊的匹配。如果你想讓c a t只和c o n c a t e n a t e匹配,則需要在格式兩端加上空格: / cat / {print} 再例如,你希望既和c a t又和C AT匹配,則可以使用或(|): / cat | CAT / {print} 在g a w k中,有幾個(gè)字符有特殊意義。下面列出可以用在g a w k格式中的這些字符: ? ^ 表示字段的開(kāi)始。 例如:$3 ~ /^b/ ???如果第三個(gè)字段以字符b開(kāi)始,則匹配。 ? $ 表示字段的結(jié)束。 例如:$3 ~ /b$/ 如果第三個(gè)字段以字符b結(jié)束,則匹配。 ? . 表示和任何單字符m匹配。 例如:$3 ~ /i.m/ 如果第三個(gè)字段有字符i,則匹配。 ? | 表示“或”。 例如:/ c a t | C AT/ 和cat 或C AT字符匹配。 ? * 表示字符的零到多次重復(fù)。 例如:/UNI*X/ 和U N X、U N I X、U N I I X、U N I I I X等匹配。 ? + 表示字符的一次到多次重復(fù)。 例如: /UNI+X/ 和U N I X、U N I I X等匹配。 ? \{a,b\} 表示字符a次到b次之間的重復(fù)。 例如: / U N I \ { 1,3 \ } X 和U N I X、U N I I X和U N I I I X匹配。 ? ? 表示字符零次和一次的重復(fù)。 例如: /UNI?X/ 和UNX 和U N I X匹配。 ? [] 表示字符的范圍。 例如: /I[BDG]M/ 和I B M、I D M和I G M匹配 ? [^] 表示不在[ ]中的字符。 例如: /I[^DE]M/ 和所有的以I開(kāi)始、M結(jié)束的包括三個(gè)字符的字符串匹配,除了I D M和I E M之外。
6.11 調(diào)用gawk程序
當(dāng)需要很多對(duì)模式和動(dòng)作時(shí),你可以編寫(xiě)一個(gè)g a w k程序(也叫做g a w k腳本)。在g a w k程序中,你可以省略模式和動(dòng)作兩邊的引號(hào),因?yàn)樵趃 a w k程序中,模式和動(dòng)作從哪開(kāi)始和從哪結(jié)束時(shí)是很顯然的。你可以使用如下命令調(diào)用g a w k程序: gawk -f script filename 此命令使g a w k對(duì)文件f i l e n a m e執(zhí)行名為s c r i p t的g a w k程序。 如果你不希望使用缺省的字段分隔符,你可以在f選項(xiàng)后面跟著F選項(xiàng)指定新的字段分隔符(當(dāng)然你也可以在g a w k程序中指定),例如,使用分號(hào)作為字段分隔符: gawk -f script -F";" filename 如果希望gawk 程序處理多個(gè)文件,則把各個(gè)文件名羅列其后: gawk -f script filename1 filename2 filename3 ... 缺省情況下, g a w k的輸出將送往屏幕。但你可以使用L i n u x的重定向命令使g a w k的輸出送往一個(gè)文件: gawk -f script filename > save_file
6.12 BEGIN和END
???有兩個(gè)特殊的模式在g a w k中非常有用。B E G I N模式用來(lái)指明g a w k開(kāi)始處理一個(gè)文件之前執(zhí)行一些動(dòng)作。B E G I N經(jīng)常用來(lái)初始化數(shù)值,設(shè)置參數(shù)等。E N D模式用來(lái)在文件處理完成后執(zhí)行一些指令,一般用作總結(jié)或注釋。 BEGIN 和E N D中所有要執(zhí)行的指令都應(yīng)該用花括號(hào)括起來(lái)。BEGIN 和E N D必須使用大寫(xiě)。 請(qǐng)看下面的例子: BEGIN { print "Starting the process the file" } $1 == "UNIX" {print} $2 > 10 {printf "This line has a value of %d",$ 2 } END { print "Finished processing the file. Bye!"} 此程序中,先顯示一條信息: Starting the process the file,然后將所有第一個(gè)字段等于U N I X的整條記錄顯示出來(lái),然后再顯示第二個(gè)字段大于10 的記錄,最后顯示信息: F i n i s h e dprocessing the file. Bye!。
6.13 變量
在g a w k中,可以用等號(hào)( = )給一個(gè)變量賦值: var1 = 10 在g a w k中,你不必事先聲明變量類型。 請(qǐng)看下面的例子: $1 == "Plastic" { count = count + 1 } 如果第一個(gè)字段是P l a s t i c,則c o u n t的值加1。在此之前,我們應(yīng)當(dāng)給c o u n t賦予過(guò)初值,一般是在B E G I N部分。 下面是比較完整的例子: BEGIN { count = 0 } $5 == "UNIX" { count = count + 1 } END { printf "%d occurrences of UNIX were found",count } 變量可以和字段和數(shù)值一起使用,所以,下面的表達(dá)式均為合法: count = count + $6 count = $5 - 8 count = $5 + var1 變量也可以是格式的一部分,例如: $2 > max_value {print "Max value exceeded by ",$2 -max_value} $4 - var1 < min_value {print "Illegal value of ",$ 4 }
6.14 內(nèi)置變量
g a w k語(yǔ)言中有幾個(gè)十分有用的內(nèi)置變量,現(xiàn)在列于下面:
NR 已經(jīng)讀取過(guò)的記錄數(shù)。 FNR 從當(dāng)前文件中讀出的記錄數(shù)。 F I L E N A M E 輸入文件的名字。 FS 字段分隔符(缺省為空格)。 RS 記錄分隔符(缺省為換行)。 OFMT 數(shù)字的輸出格式(缺省為% g)。 OFS 輸出字段分隔符。 ORS 輸出記錄分隔符。 NF 當(dāng)前記錄中的字段數(shù)。
如果你只處理一個(gè)文件,則NR 和FNR 的值是一樣的。但如果是多個(gè)文件, N R是對(duì)所有的文件來(lái)說(shuō)的,而FNR 則只是針對(duì)當(dāng)前文件而言。例如: NR <= 5 {print "Not enough fields in the record"} 檢查記錄數(shù)是否小于5,如果小于5,則顯示出錯(cuò)信息。 F S十分有用,因?yàn)镕 S控制輸入文件的字段分隔符。例如,在B E G I N格式中,使用如下的 命令: F S = " : "
6.15 控制結(jié)構(gòu)
6.15.1 if 表達(dá)式
if 表達(dá)式的語(yǔ)法如下: if (expression){ c o m m a n d s } e l s e { c o m m a n d s } 例如: # a simple if loop (if ($1 == 0){ print "This cell has a value of zero" } else { printf "The value is %d\n",$ 1 } ) 再看下一個(gè)例子: # a nicely formatted if loop (if ($1 > $2){ print "The first column is larger" } else { print "The second column is larger" } )
6.15.2 while 循環(huán) while 循環(huán)的語(yǔ)法如下: while (expression){ c o m m a n d s } 例如: # interest calculation computes compound interest # inputs from a file are the amount,interest_rateand years {var = 1 while (var <= $3) { p r i n t f ( " % f \ n ",$ 1 * ( 1 + $ 2 ) ^ v a r ) v a r + +} }
6.15.3 for 循環(huán)
for 循環(huán)的語(yǔ)法如下: for (initialization; expression; increment) { c o m m a n d } 例如: # interest calculation computes compound interest # inputs from a file are the amount,interest_rateand years {for (var=1; var <= $3; var++) { p r i n t f ( " % f \ n ",$ 1 * ( 1 + $ 2 ) ^ v a r ) } } 6.15.4 next 和exit
next 指令用來(lái)告訴gawk 處理文件中的下一個(gè)記錄, 而不管現(xiàn)在正在做什么。語(yǔ)法如下: { command1 c o m m a n d 2 c o m m a n d 3 n e x t c o m m a n d 4 } ???程序只要執(zhí)行到n e x t指令,就跳到下一個(gè)記錄從頭執(zhí)行命令。因此,本例中, c o m m a n d 4指令永遠(yuǎn)不會(huì)被執(zhí)行。 ???程序遇到e x i t指令后,就轉(zhuǎn)到程序的末尾去執(zhí)行E N D,如果有E N D的話。
6.16 數(shù)組
g a w k語(yǔ)言支持?jǐn)?shù)組結(jié)構(gòu)。數(shù)組不必事先初始化。聲明一個(gè)數(shù)組的方法如下: a r r a y n a m e [ n u m ] = v a l u e 請(qǐng)看下面的例子: # reverse lines in a file {line[NR] = $0 } # remember each line END {var=NR # output lines in reverse order while (var > 0){ print line[var] v a r - - } } 此段程序讀取一個(gè)文件的每一行,并用相反的順序顯示出來(lái)。我們使用N R作為數(shù)組的下標(biāo)來(lái)存儲(chǔ)文件的每一條記錄,然后在從最后一條記錄開(kāi)始,將文件逐條地顯示出來(lái)。
6.17 用戶自定義函數(shù)
復(fù)雜的gawk 程序常常可以使用自己定義的函數(shù)來(lái)簡(jiǎn)化。調(diào)用用戶自定義函數(shù)與調(diào)用內(nèi)部函數(shù)的方法一樣。函數(shù)的定義可以放在gawk 程序的任何地方。 用戶自定義函數(shù)的格式如下: function name (parameter-list) { b o d y - o f - f u n c t i o n } name 是所定義的函數(shù)的名稱。一個(gè)正確的函數(shù)名稱可包括一序列的字母、數(shù)字、下標(biāo)線( u n d e r s c o r e s ),但是不可用數(shù)字做開(kāi)頭。p a r a m e t e r-list 是函數(shù)的全部參數(shù)的列表,各個(gè)參數(shù)之間以逗點(diǎn)隔開(kāi)。body-of-function 包含gawk 的表達(dá)式,它是函數(shù)定義里最重要的部分,它決定函數(shù)實(shí)際要做的事情。 下面這個(gè)例子,會(huì)將每個(gè)記錄的第一個(gè)字段的值的平方與第二個(gè)字段的值的平方加起來(lái)。 {print "sum =",S q u a r e S u m ( $ 1,$ 2 ) } function SquareSum(x,y) { s u m = x * x + y * y return sum } ???到此,我們已經(jīng)知道了g a w k的基本用法。g a w k語(yǔ)言十分易學(xué)好用,例如,你可以用g a w k編寫(xiě)一段小程序來(lái)計(jì)算一個(gè)目錄中所有文件的個(gè)數(shù)和容量。如果用其他的語(yǔ)言,如C語(yǔ)言,則會(huì)十分的麻煩,相反,g a w k只需要幾行就可以完成此工作。
6.18 幾個(gè)實(shí)例
最后,再舉幾個(gè)g a w k的例子: gawk '{if (NF > max) max = NF} END {print max}' 此程序會(huì)顯示所有輸入行之中字段的最大個(gè)數(shù)。 gawk 'length($0) > 80' 此程序會(huì)顯示出超過(guò)80 個(gè)字符的每一行。此處只有模式被列出,動(dòng)作是采用缺省值顯示整個(gè)記錄。 gawk 'NF > 0' 顯示擁有至少一個(gè)字段的所有行。這是一個(gè)簡(jiǎn)單的方法,將一個(gè)文件里的所有空白行刪除。 gawk 'BEGIN {for (i = 1; i <= 7; i++) print int(101 * rand())}' 此程序會(huì)顯示出范圍是0 到100 之間的7 個(gè)隨機(jī)數(shù)。 ls -l files | gawk '{x += $4}; END {print "total bytes: " x}' 此程序會(huì)顯示出所有指定的文件的總字節(jié)數(shù)。 expand file | gawk '{if (x < length()) x = length()} END {print "maximum line length is " x}' 此程序會(huì)將指定文件里最長(zhǎng)一行的長(zhǎng)度顯示出來(lái)。expand 會(huì)將tab 改成s p a c e,所以是用實(shí)際的右邊界來(lái)做長(zhǎng)度的比較。 gawk 'BEGIN {FS = ":"} {print $1 | "sort"}' /etc/passwd 此程序會(huì)將所有用戶的登錄名稱,依照字母的順序顯示出來(lái)。 gawk '{nlines++} END {print nlines}' 此程序會(huì)將一個(gè)文件的總行數(shù)顯示出來(lái)。 gawk 'END {print NR}' 此程序也會(huì)將一個(gè)文件的總行數(shù)顯示出來(lái),但是計(jì)算行數(shù)的工作由g a w k來(lái)做。 gawk '{print NR,$ 0 } ' 此程序顯示出文件的內(nèi)容時(shí),會(huì)在每行的最前面顯示出行號(hào),它的函數(shù)與‘ cat -n’類似。
|