Ubuntu Shell命令awk程序中使用
Ubuntu Shell 對(duì)于電腦使用的玩家的常用軟件,然后我就學(xué)習(xí)及深入的研究Ubuntu Shell ,在這里和大家一起探討Ubuntu Shell 的使用方法,希望對(duì)大家有用。
awk程序中使用 Ubuntu Shell 命令
awk程序中允許呼叫Ubuntu Shell指令. 并提供管道解決awk與系統(tǒng)間數(shù)據(jù)傳遞的問(wèn)題. 所以awk很容易使用系統(tǒng)資源. 讀者可利用這個(gè)特點(diǎn)來(lái)編寫(xiě)某些適用的系統(tǒng)工具.
寫(xiě)一個(gè)awk程序來(lái)打印出線上人數(shù). 將下列程序建文件, 命名為 count.awk BEGIN { while ( "who" | getline ) n++ print n } 并執(zhí)行下列命令 : awk -f count.awk 執(zhí)行結(jié)果將會(huì)印出目前在線人數(shù)
awk 程序并不一定要處理數(shù)據(jù)文件. 以本例而言, 僅輸入程序文件count.awk, 未輸入任何數(shù)據(jù)文件. BEGIN 和 END 同為awk中的一種 Pattern. 以 BEGIN 為 Pattern的Actions ,只有在awk開(kāi)始執(zhí)行程序,尚未開(kāi)啟任何輸入文件前, 被執(zhí)行一次.(注意: 只被執(zhí)行一次)
"|" 為 awk 中表示管道的符號(hào). awk 把 | 之前的字符串"who"當(dāng)成Ubuntu Shell上的命令, 并將該命令送往Ubuntu Shell執(zhí)行, 執(zhí)行的結(jié)果(原先應(yīng)于屏幕印出者)則藉由pipe送進(jìn)awk程序中. getline為awk所提供的輸入指令.
其語(yǔ)法如下 : 語(yǔ)法由何處讀取數(shù)據(jù)數(shù)據(jù)讀入后置于getline var < file所指定的 file變量 var(var省略時(shí),表示置于$0)getline varpipe 變量變量 var(var省略時(shí),表示置于$0)
getline var見(jiàn) 注一 變量 var(var省略時(shí),表示置于$0)
注一 : 當(dāng) Pattern 為 BEGIN 或 END 時(shí), getline 將由 stdin 讀取數(shù)據(jù), 否則由awk正處理的數(shù)據(jù)文件上讀取數(shù)據(jù). getline 一次讀取一行數(shù)據(jù), 若讀取成功則return 1, 若讀取失敗則return -1, 若遇到文件結(jié)束(EOF), 則return 0;
本程序使用 getline 所 return 的數(shù)據(jù)來(lái)做為 while 判斷循環(huán)停止的條件,某些awk版本較舊,并不容許使用者改變 $0 之值. 這種版的 awk 執(zhí)行本程序時(shí)會(huì)產(chǎn)生 Error, 讀者可于 getline 之后置上一個(gè)變量 (如此, getline 讀進(jìn)來(lái)的數(shù)據(jù)便不會(huì)被置于 $0 ), 或直接改用gawk便可解決.
awk 程序的應(yīng)用實(shí)例
本節(jié)將示范一個(gè)統(tǒng)計(jì)上班到達(dá)時(shí)間及遲到次數(shù)的程序. 這程序每日被執(zhí)行時(shí)將讀入二個(gè)文件: 員工當(dāng)日到班時(shí)間的數(shù)據(jù)文件 ( 如下列之 arr.dat ) 存放員工當(dāng)月遲到累計(jì)次數(shù)的文件. 當(dāng)程序執(zhí)行執(zhí)完畢后將更新第二個(gè)文件的數(shù)據(jù)(遲到次數(shù)), 并打印當(dāng)日的報(bào)表.這程序?qū)⒎殖上铝袛?shù)小節(jié)逐步完成, 其大綱如下:
在到班資料文件 arr.dat 之前增加一行抬頭 "ID Number Arrvial Time", 并產(chǎn)生報(bào)表輸出到文件today_rpt1 中.< 思考: 在awk中如何將數(shù)據(jù)輸出到文件 > 將 today_rpt1 上的數(shù)據(jù)按員工代號(hào)排序, 并加注執(zhí)行當(dāng)日日期; 產(chǎn)生文件 today_rpt2 <思考 awk中如何運(yùn)用系統(tǒng)資源及awk中Pipe之特性 >
將awk程序包含在一個(gè)Ubuntu Shell script文件中于 today_rpt2 每日?qǐng)?bào)表上, 遲到者之前加上"*", 并加注當(dāng)日平均到班時(shí)間;產(chǎn)生文件 today_rpt3 從文件中讀取當(dāng)月遲到次數(shù), 并根據(jù)當(dāng)日出勤狀況更新遲到累計(jì)數(shù). <思考 使用者在awk中如何讀取文件數(shù)據(jù) >
重定向輸出到文件
awk中并未提供如 C 語(yǔ)言中之fopen() 指令, 也未有fprintf() 文件輸出這樣的指令. 但awk中任何輸出函數(shù)之后皆可借助使用與UNIX 中類(lèi)似的 I/O 重定向符, 將輸出的數(shù)據(jù)重定向到指定的文件; 其符號(hào)仍為 > (輸出到一個(gè)新產(chǎn)生的文件) 或 >> ( 添加輸出的數(shù)據(jù)到文件末尾 ).
[例 :]在到班數(shù)據(jù)文件 arr.dat 之前增加一行抬頭如下: "ID Number Arrival Time", 并產(chǎn)生報(bào)表輸出到文件 today_rpt1中 建立如下文件并取名為reformat1.awk BEGIN { print " ID Number Arrival Time" > "today_rpt1" print "===========================" > "today_rpt1" } { printf(" %s %s"n", $1,$2 ) > "today_rpt1" }
執(zhí)行: $awk -f reformat1.awk arr.dat 執(zhí)行后將產(chǎn)生文件 today_rpt1, 其內(nèi)容如下 : ID Number Arrival Time awk程序中, 文件名稱(chēng) today_rpt1 的前后須以" (雙引號(hào))括住, 表示 today_rpt1 為一字符串常量. 若未以"括住, 則 today_rpt1 將被awk解釋為一個(gè)變量名稱(chēng). 在awk中任何變量使用之前, 并不須事先聲明.
其初始值為空字符串(Null string) 或 0.因此程序中若未以 " 將 today_rpt1 括住, 則 today_rpt1 將是一變量, 其值將是空字符串, 這會(huì)在執(zhí)行時(shí)造成錯(cuò)誤(Unix 無(wú)法幫您開(kāi)啟一個(gè)以空字符串為文件名的文件).
因此在編輯awk程序時(shí), 須格外留心. 因?yàn)槿羟缅e(cuò)變量名稱(chēng),awk在編譯程序時(shí)會(huì)認(rèn)為是一新的變量, 并不會(huì)察覺(jué). 因此往往會(huì)造成運(yùn)行時(shí)錯(cuò)誤. BEGIN 為awk的保留字, 是 Pattern 的一種. 以 BEGIN 為 Pattern 的 Actions 于awk程序剛被執(zhí)行尚未讀取數(shù)據(jù)文件時(shí)被執(zhí)行一次, 此后便不再被執(zhí)行.
讀者或許覺(jué)得本程序中的I/O重定向符號(hào)應(yīng)使用 " >>" (append)而非 " >". 本程序中若使用 ">" 將數(shù)據(jù)重導(dǎo)到 today_rpt1, awk 第一次執(zhí)行該指令時(shí)會(huì)產(chǎn)生一個(gè)新檔 today_rpt1, 其后再執(zhí)行該指令時(shí)則把數(shù)據(jù)追加到today_rpt1文件末, 并非每執(zhí)行一次就重開(kāi)一個(gè)新文件.
若采用">>"其差異僅在第一次執(zhí)行該指令時(shí), 若已存在today_rpt1則 awk 將直接把數(shù)據(jù)append在原文件之末尾. 這一點(diǎn), 與UNIX中的用法不同.
awk 中如何利用系統(tǒng)資源
awk程序中很容易使用系統(tǒng)資源. 這包括在程序中途調(diào)用 Ubuntu Shell 命令來(lái)處理程序中的部分?jǐn)?shù)據(jù); 或在調(diào)用 Ubuntu Shell 命令后將其產(chǎn)生的結(jié)果交回 awk 程序(不需將結(jié)果暫存于某個(gè)文件). 這一過(guò)程是借助 awk 所提供的管道 (雖然有些類(lèi)似 Unix 中的管道, 但特性有些不同),及一個(gè)從 awk 中呼叫 Unix 的 Ubuntu Shell 命令的語(yǔ)法來(lái)達(dá)成的.
承上題, 將數(shù)據(jù)按員工ID排序后再輸出到文件 today_rpt2 , 并于表頭附加執(zhí)行時(shí)的日期. awk 提供與 UNIX 用法近似的 pipe, 其記號(hào)亦為 "|". 其用法及含意如下 : awk程序中可接受下列兩種語(yǔ)法:
[a. 語(yǔ)法] awk output 指令 | "Ubuntu Shell 接受的命令" ( 如 : print $1,$2 | "sort -k 1" ) [b. 語(yǔ)法] "Ubuntu Shell 接受的命令" | awk input 指令 ( 如 : "ls " | getline)
注 : awk input 指令只有 getline 一個(gè). awk output 指令有 print, printf() 二個(gè). 在a 語(yǔ)法中, awk所輸出的數(shù)據(jù)將轉(zhuǎn)送往 Ubuntu Shell , 由 Ubuntu Shell 的命令進(jìn)行處理.以上例而言, print 所輸出的數(shù)據(jù)將經(jīng)由 Ubuntu Shell 命令 "sort -k 1" 排序后再送往屏幕(stdout).
上列awk程序中, "print$1, $2" 可能反復(fù)執(zhí)行很多次, 其輸出的結(jié)果將先暫存于 pipe 中,等到該程序結(jié)束時(shí), 才會(huì)一并進(jìn)行 "sort -k 1". 須注意二點(diǎn) : 不論 print $1, $2 被執(zhí)行幾次, "sort -k 1" 的執(zhí)行時(shí)間是 "awk程序結(jié)束時(shí)",
"sort -k 1" 的執(zhí)行次數(shù)是 "一次". 在 b 語(yǔ)法中, awk將先調(diào)用 Ubuntu Shell 命令. 其執(zhí)行結(jié)果將通過(guò) pipe 送入awk程序,以上例而言, awk先讓 Ubuntu Shell 執(zhí)行 "ls",Ubuntu Shell 執(zhí)行后將結(jié)果存于 pipe, awk指令 getline再?gòu)?pipe 中讀取數(shù)據(jù).
使用本語(yǔ)法時(shí)應(yīng)留心: 以上例而言,awk "立刻"調(diào)用 Ubuntu Shell 來(lái)執(zhí)行 "ls", 執(zhí)行次數(shù)是一次. getline 則可能執(zhí)行多次(若pipe中存在多行數(shù)據(jù)). 除上列 a, b 二中語(yǔ)法外, awk程序中其它地方如出現(xiàn)像 "date", "cls", "ls"... 這樣的字符串, awk只把它當(dāng)成一般字符串處理.
建立如下文件并取名為 reformat2.awk # 程序 reformat2.awk # 這程序用以練習(xí)awk中的pipe BEGIN { "date" | getline # Ubuntu Shell 執(zhí)行 "date". getline 取得結(jié)果并以$0記錄 print " Today is " , $2, $3 >"today_rpt2" print "=========================" > "today_rpt2" print " ID Number Arrival Time" >"today_rpt2" close( "today_rpt2" ) } {printf( "%s %s"n", $1 ,$2 ) | "sort -k 1 >>today_rpt2"}
執(zhí)行如下命令: awk -f reformat2.awk arr.dat 執(zhí)行后, 系統(tǒng)會(huì)自動(dòng)將 sort 后的數(shù)據(jù)追加( Append; 因?yàn)槭褂?" >>") 到文件 today_rpt2末端. today_rpt2 內(nèi)容如下 : awk程序由三個(gè)主要部分構(gòu)成 :
[ i.] Pattern { Action} 指令 [ ii.] 函數(shù)主體. 例如 : function double( x ){ return 2*x } (參考第11節(jié) Recursive Program ) [ iii.] Comment ( 以 # 開(kāi)頭識(shí)別之 )
awk 的輸入指令 getline, 每次讀取一列數(shù)據(jù). 若getline之后未接任何變量, 則所讀入之資料將以$0 記錄, 否則以所指定的變量?jī)?chǔ)存之.
執(zhí)行 "date" | getline 后, $0 之值為 "2007年 09月 21日 星期五 14:28:02 CST",當(dāng) $0 之值被更新時(shí), awk將自動(dòng)更新相關(guān)的內(nèi)建變量, 如: $1,$2,..,NF.故 $2 之值將為"09月", $3之值將為"21日".
(有少數(shù)舊版的awk不允許即使用者自行更新(update)$0的值,或者更新$0時(shí),它不會(huì)自動(dòng)更新 $1,$2,..NF. 這情況下, 可改用gawk或nawk. 否則使用者也可自行以awk字符串函數(shù)split()來(lái)分隔$0上的數(shù)據(jù))
本程序中 printf() 指令會(huì)被執(zhí)行12次( 因?yàn)橛衋rr.dat中有12行數(shù)據(jù)), 但讀者不用擔(dān)心數(shù)據(jù)被重復(fù)sort了12次. 當(dāng)awk結(jié)束該程序時(shí)才會(huì) close 這個(gè) pipe , 此時(shí)才將這12行數(shù)據(jù)一次送往系統(tǒng),并呼叫 "sort -k 1 >> today_rpt2" 處理之.
awk提供另一個(gè)調(diào)用Ubuntu Shell命令的方法, 即使用awk函數(shù)system("Ubuntu Shell命令") 例如: $ awk ' BEGIN{ system("date > date.dat") getline < "date.dat"print "Today is ", $2, $3 }' 但使用 system( "Ubuntu Shell 命令" ) 時(shí), awk無(wú)法直接將執(zhí)行中的部分?jǐn)?shù)據(jù)輸出給Ubuntu Shell 命令. 且 Ubuntu Shell 命令執(zhí)行的結(jié)果也無(wú)法直接輸入到awk中.
【編輯推薦】