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